1. Libraries and functions

1.1 Libraries

Load the required libraries.

library(tidyverse)
library(sf)
library(here)
library(readxl)
library(scales)
library(DT)
library(brms)
library(tidybayes)
library(patchwork)
library(marginaleffects)
library(ggrepel)
library(scico)
library(ggdensity)
library(ggpubr)

1.2 Helper functions

Functions that we will use throughout the script

#labeller for years
year_labels <- c(1950:1963)

#The Glasgow mass minuture chest X-ray campaign happened between 11th March and 12th April 1957
#Segment for graphs to match ACF period
acf_start <- decimal_date(ymd("1957-03-11"))
acf_end <- decimal_date(ymd("1957-04-12"))

Function for counterfactual plots


plot_counterfactual <- function(model_data, model, population_denominator, outcome, grouping_var=NULL, ...){
  
  #labeller for years
  year_labels <- c(1950:1963)

  #The Glasgow mass minuture chest X-ray campaign happened between 11th March and 12th April 1957
  #Segment for graphs to match ACF period
  acf_start <- decimal_date(ymd("1957-03-11"))
  acf_end <- decimal_date(ymd("1957-04-12"))

  summary <- {{model_data}} %>%
    select(year, year2, y_num, acf_period, {{population_denominator}}, {{outcome}}, {{grouping_var}}) %>%
    add_epred_draws({{model}}) %>%
    group_by(year2, acf_period, {{grouping_var}}) %>%
    mean_qi() %>%
    mutate(.epred_inc = .epred/{{population_denominator}}*100000,
          .epred_inc.lower = .epred.lower/{{population_denominator}}*100000,
          .epred_inc.upper = .epred.upper/{{population_denominator}}*100000) %>%
    mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                  acf_period=="c. post-acf" ~ "Post Intervention"))



  #create the counterfactual (no intervention), and summarise
  
  counterfact <-
    add_epred_draws(object = {{model}},
                    newdata = {{model_data}} %>%
                                  select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, {{outcome}}) %>%
                                  mutate(acf_period = "a. pre-acf")) %>%
    group_by(year2, acf_period, {{grouping_var}}) %>%
    mean_qi() %>%
    mutate(.epred_inc = .epred/{{population_denominator}}*100000,
         .epred_inc.lower = .epred.lower/{{population_denominator}}*100000,
         .epred_inc.upper = .epred.upper/{{population_denominator}}*100000) %>%
    mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                acf_period=="c. post-acf" ~ "Post Intervention"))
  


  #plot the intervention effect
p <- summary %>%
    droplevels() %>%
    ggplot() +
    geom_ribbon(aes(ymin=.epred_inc.lower, ymax=.epred_inc.upper, x=year2, group = acf_period, fill=acf_period), alpha=0.5) +
    geom_ribbon(data = counterfact %>% filter(year>=1956), 
                aes(ymin=.epred_inc.lower, ymax=.epred_inc.upper, x=year2, fill="Counterfactual"), alpha=0.5) +
    geom_line(data = counterfact %>% filter(year>=1956), 
              aes(y=.epred_inc, x=year2, colour="Counterfactual")) +
    geom_line(aes(y=.epred_inc, x=year2, group=acf_period,  colour=acf_period)) +
    geom_point(data = {{model_data}}, aes(y={{outcome}}, x=year2, shape=acf_period), size=2) +
    geom_vline(aes(xintercept=acf_end), linetype=3) +
    theme_ggdist() +
    scale_y_continuous(labels=comma) +
    scale_x_continuous(labels = year_labels,
                       breaks = year_labels) +
    scale_fill_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="") +
    scale_colour_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="") +
    scale_shape_discrete(name="") +
    labs(
      x = "Year",
      y = "Case notification rate (per 100,000)",
      caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
    ) +
    theme(legend.position = "bottom",
          panel.border = element_rect(colour = "grey78", fill=NA),
          title = element_text(size=14),
          axis.text.x = element_text(size=10, angle = 90, hjust=1, vjust=0.5),
          legend.text = element_text(size=12)) +
    guides(shape="none")

    facet_vars <- vars(...)

  if (length(facet_vars) != 0) {
    p <- p + facet_wrap(facet_vars)
  }
  p

}

Function for calculating measures of change over time


summarise_change <- function(model_data, model, population_denominator, grouping_var=NULL){

  #a. immediate change
  nd_immediate <- {{model_data}} %>%
    filter(year %in% c(1956:1957)) %>%
    select(acf_period, year, y_num, {{population_denominator}}, {{grouping_var}})

  #Calcuate incidence per draw, then summarise.
  immediate_change <- add_epred_draws({{model}},
                                      newdata=nd_immediate) %>%
    mutate(epred_inc100k = .epred/{{population_denominator}}) %>%
    group_by(.draw, {{grouping_var}}) %>%
    mutate(acf_inc100k_diff = last(epred_inc100k)-first(epred_inc100k),
           acf_inc100k_rr = last(epred_inc100k)/first(epred_inc100k)) %>%
    ungroup() %>%
    group_by({{grouping_var}}) %>%
    mean_qi(acf_inc100k_diff, acf_inc100k_rr) %>%
    mutate(change = "Immediate change") %>%
    ungroup()
  
  #b. post-ACF change
  nd_post <- {{model_data}} %>%
    filter(year %in% c(1956,1958)) %>%
    select(acf_period, year, y_num, {{population_denominator}}, {{grouping_var}})

  #Calcuate incidence per draw, then summarise.
  post_change <- add_epred_draws({{model}},
                                      newdata=nd_post) %>%
    mutate(epred_inc100k = .epred/{{population_denominator}}) %>%
    group_by(.draw, {{grouping_var}}) %>%
    mutate(acf_inc100k_diff = last(epred_inc100k)-first(epred_inc100k),
           acf_inc100k_rr = last(epred_inc100k)/first(epred_inc100k)) %>%
    ungroup() %>%
    group_by({{grouping_var}}) %>%
    mean_qi(acf_inc100k_diff, acf_inc100k_rr) %>%
    mutate(change = "Post-ACF change") %>%
    ungroup()
  
  #c. change in slope post vs. pre-ACF
  slope_change <- {{model_data}} %>%
    select(year, year2, y_num, acf_period, {{population_denominator}}, {{grouping_var}}) %>%
    filter(year!=1957) %>%
    add_epred_draws({{model}}) %>%
    mutate(inc_100k = .epred/{{population_denominator}}*100000) %>%
    group_by(year, {{grouping_var}}, acf_period, ) %>%
    mean_qi(inc_100k) %>%
    ungroup() %>%
    mutate(n_years = length(year), .by=c(acf_period, {{grouping_var}})) %>%
    summarise(pct_change_epred_overall = (((last(inc_100k) - first(inc_100k))/first(inc_100k))),
              pct_change_lower_overall = (((last(.lower) - first(.lower))/first(.lower))),
              pct_change_upper_overall = (((last(.upper) - first(.upper))/first(.upper))),
      
              pct_change_epred_annual = (((last(inc_100k) - first(inc_100k))/first(inc_100k))/n_years),
              pct_change_lower_annual = (((last(.lower) - first(.lower))/first(.lower))/n_years),
              pct_change_upper_annual = (((last(.upper) - first(.upper))/first(.upper))/n_years),
              .by = c(acf_period, {{grouping_var}})) %>%
    distinct() %>%
    mutate(change = "Slope change")

  lst(immediate_change, post_change, slope_change)
    
}

Function for calculating difference from counterfactual

calcuate_counterfactual <- function(model_data, model, population_denominator, grouping_var=NULL){
  
  #effect in 1958 vs. counterfactual
  counterfact <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}) %>%
                                    mutate(acf_period = "a. pre-acf")) %>%
      group_by(.draw, year, {{grouping_var}}, acf_period) %>%
      mutate(.epred_inc_counterf = .epred/{{population_denominator}}*100000, .epred_counterf=.epred)  %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, {{population_denominator}}, .draw, .epred_counterf, .epred_inc_counterf)
  
  #Calcuate incidence per draw, then summarise.
  post_change <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, acf_period)) %>%
      group_by(.draw, year, {{grouping_var}}, acf_period) %>%
      mutate(.epred_inc = .epred/{{population_denominator}}*100000)  %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, {{population_denominator}}, {{grouping_var}}, .draw, .epred, .epred_inc) 
  
counter_post <-
  left_join(counterfact, post_change) %>%
    mutate(cases_averted = .epred_counterf-.epred,
          diff_inc100k = .epred_inc - .epred_inc_counterf,
           rr_inc100k = .epred_inc/.epred_inc_counterf,
           pct_inc100k = (.epred_inc - .epred_inc_counterf)/.epred_inc) %>%
    group_by(year, {{grouping_var}}) %>%
    mean_qi(cases_averted, diff_inc100k, rr_inc100k, pct_inc100k) %>%
    ungroup()

lst(counter_post)

}

2. Data

Import datasets for analysis

2.1 Shapefiles


glasgow_wards_1951 <- st_read("glasgow_wards_1959.geojson")
Reading layer `glasgow_wards_1959' from data source `/Users/petermacpherson/Dropbox/Projects/Historical TB ACF 2023-11-28/Work/Data/glasgow_wards_1959.geojson' using driver `GeoJSON'
Simple feature collection with 37 features and 3 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 44.2138 ymin: -2611.823 xmax: 3193.173 ymax: -223.6828
Geodetic CRS:  WGS 84

3. Denominators

Load in the datasets for denonomiators, and check for consistency.


overall_pops <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "overall_population")

overall_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()

#shift year to midpoint
overall_pops <- overall_pops %>%
  mutate(year2 = year+0.5)

Note, we have three population estimates:

  1. Population without institutionalised people or people in shipping
  2. Population in institutions
  3. Population in shipping

(Population in shipping is estimated from the 1951 census, so is the same for most years)

3.1 Overall population

First, plot the total population


overall_pops %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2), alpha=0.5, colour = "mediumseagreen", fill="mediumseagreen") +
  geom_point(aes(y=total_population, x=year2), colour = "mediumseagreen") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(
    title = "Glasgow Corporation: total population",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist()

NA
NA

Now the population excluding institutionalised and shipping population


overall_pops %>%
  ggplot() +
  geom_area(aes(y=population_without_inst_ship, x=year2), alpha=0.5, colour = "purple", fill="purple") +
  geom_point(aes(y=population_without_inst_ship, x=year2), colour = "purple") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(
    title = "Glasgow Corporation: population excluding institutionalised and shipping",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist()

NA
NA

3.2 Population by Ward

There are 5 Divisions containing 37 Wards in the Glasgow Corporation, with consistent boundaries over time.

#look-up table for divisions and wards
ward_lookup <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "divisions_wards")


ward_pops <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "ward_population")

ward_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()

#shift year to midpoint
ward_pops <- ward_pops %>%
  mutate(year2 = year+0.5)

#Get the Division population
division_pops <- ward_pops %>%
  group_by(division, year) %>%
  summarise(population_without_inst_ship = sum(population_without_inst_ship, na.rm = TRUE),
            institutions = sum(institutions, na.rm = TRUE),
            shipping = sum(shipping, na.rm = TRUE),
            total_population = sum(total_population, na.rm = TRUE))
`summarise()` has grouped output by 'division'. You can override using the `.groups` argument.
division_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA

Plot the overall population by Division and Ward


division_pops %>%
  mutate(year2 = year+0.5) %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2, colour=division, fill=division), alpha=0.5) +
  geom_point(aes(y=total_population, x=year2, colour=division)) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  facet_wrap(division~.) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  scale_fill_viridis_d(name = "") +
  scale_colour_viridis_d(name = "") +
  labs(
    title = "Glasgow Corporation: total population by Division",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA

ward_pops %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2, colour=division, fill=division), alpha=0.5) +
  geom_point(aes(y=total_population, x=year2, colour=division)) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  facet_wrap(ward~., ncol=6) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  scale_fill_viridis_d(name = "Division") +
  scale_colour_viridis_d(name = "Division") +
  labs(
    title = "Glasgow City: total population by Ward",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

ggsave(here("figures/s1.png"), height=10, width=12)

Approximately, how many person-years of follow-up do we have?


overall_pops %>%
  ungroup() %>%
  summarise(across(year, length, .names = "years"),
            across(c(population_without_inst_ship, total_population), sum)) %>%
  mutate(across(where(is.double), comma)) %>%
  datatable()
NA
NA

Change in population by ward


ward_pops %>%
  group_by(ward) %>%
  summarise(pct_change_pop = (last(population_without_inst_ship) - first(population_without_inst_ship))/first(population_without_inst_ship)) %>%
  mutate(pct_change_pop = percent(pct_change_pop)) %>%
  arrange(pct_change_pop) %>%
  datatable()
NA
NA
NA

3.3 Population by age and sex


age_sex <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "age_sex_population") %>%
  pivot_longer(cols = c(male, female),
               names_to = "sex")

#collapse down to smaller age groups to be manageable
age_sex <- age_sex %>%
  ungroup() %>%
  mutate(age = case_when(age == "0 to 4" ~ "00 to 04",
                         age == "5 to 9" ~ "05 to 14",
                         age == "10 to 14" ~ "05 to 14",
                         age == "15 to 19" ~ "15 to 24",
                         age == "20 to 24" ~ "15 to 24",
                         age == "25 to 29" ~ "25 to 34",
                         age == "30 to 34" ~ "25 to 34",
                         age == "35 to 39" ~ "35 to 44",
                         age == "40 to 44" ~ "35 to 44",
                         age == "45 to 49" ~ "45 to 59",
                         age == "50 to 54" ~ "45 to 59",
                         age == "55 to 59" ~ "45 to 59",
                         TRUE ~ "60 & up")) %>%
  group_by(year, age, sex) %>%
  mutate(value = sum(value)) %>%
  ungroup()



m_age_sex <- lm(value ~ splines::ns(year, knots = 3)*age*sex, data = age_sex)

summary(m_age_sex)
Warning: essentially perfect fit: summary may be unreliable

Call:
lm(formula = value ~ splines::ns(year, knots = 3) * age * sex, 
    data = age_sex)

Residuals:
       Min         1Q     Median         3Q        Max 
-1.185e-10  0.000e+00  0.000e+00  0.000e+00  1.185e-10 

Coefficients: (14 not defined because of singularities)
                                                    Estimate Std. Error    t value Pr(>|t|)    
(Intercept)                                        5.222e+04  2.040e-10  2.559e+14   <2e-16 ***
splines::ns(year, knots = 3)1                     -8.043e+03  4.071e-10 -1.976e+13   <2e-16 ***
splines::ns(year, knots = 3)2                             NA         NA         NA       NA    
age05 to 14                                        3.669e+04  2.499e-10  1.468e+14   <2e-16 ***
age15 to 24                                       -3.893e+03  2.499e-10 -1.558e+13   <2e-16 ***
age25 to 34                                       -3.996e+04  2.499e-10 -1.599e+14   <2e-16 ***
age35 to 44                                       -4.230e+04  2.499e-10 -1.693e+14   <2e-16 ***
age45 to 59                                        5.459e+04  2.356e-10  2.317e+14   <2e-16 ***
age60 & up                                         7.533e+04  2.204e-10  3.418e+14   <2e-16 ***
sexmale                                            3.374e+03  2.886e-10  1.169e+13   <2e-16 ***
splines::ns(year, knots = 3)1:age05 to 14         -1.863e+03  4.985e-10 -3.737e+12   <2e-16 ***
splines::ns(year, knots = 3)2:age05 to 14                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age15 to 24          7.533e+04  4.985e-10  1.511e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age15 to 24                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age25 to 34          1.325e+05  4.985e-10  2.658e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age25 to 34                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age35 to 44          1.380e+05  4.985e-10  2.769e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age35 to 44                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age45 to 59          3.474e+03  4.700e-10  7.390e+12   <2e-16 ***
splines::ns(year, knots = 3)2:age45 to 59                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age60 & up          -8.453e+04  4.397e-10 -1.923e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age60 & up                  NA         NA         NA       NA    
splines::ns(year, knots = 3)1:sexmale             -1.994e+03  5.757e-10 -3.464e+12   <2e-16 ***
splines::ns(year, knots = 3)2:sexmale                     NA         NA         NA       NA    
age05 to 14:sexmale                                1.053e+04  3.534e-10  2.980e+13   <2e-16 ***
age15 to 24:sexmale                                2.352e+04  3.534e-10  6.656e+13   <2e-16 ***
age25 to 34:sexmale                                1.355e+04  3.534e-10  3.833e+13   <2e-16 ***
age35 to 44:sexmale                               -1.727e+03  3.534e-10 -4.888e+12   <2e-16 ***
age45 to 59:sexmale                                2.774e+03  3.332e-10  8.324e+12   <2e-16 ***
age60 & up:sexmale                                -7.761e+04  3.117e-10 -2.490e+14   <2e-16 ***
splines::ns(year, knots = 3)1:age05 to 14:sexmale -2.049e+04  7.051e-10 -2.906e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age05 to 14:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age15 to 24:sexmale -6.780e+04  7.051e-10 -9.616e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age15 to 24:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age25 to 34:sexmale -3.804e+04  7.051e-10 -5.396e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age25 to 34:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age35 to 44:sexmale -1.171e+04  7.051e-10 -1.661e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age35 to 44:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age45 to 59:sexmale -3.473e+04  6.647e-10 -5.224e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age45 to 59:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age60 & up:sexmale   1.056e+05  6.218e-10  1.698e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age60 & up:sexmale          NA         NA         NA       NA    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 3.074e-11 on 44 degrees of freedom
Multiple R-squared:      1, Adjusted R-squared:      1 
F-statistic: 6.006e+29 on 27 and 44 DF,  p-value: < 2.2e-16
age_levels <- age_sex %>% select(age) %>% distinct() %>% pull() 

age_sex_nd <- 
  crossing(
    age=age_levels,
    sex=c("male", "female"),
    year = 1950:1963
  )

pred_pops <- age_sex_nd %>% modelr::add_predictions(m_age_sex)
Warning: prediction from a rank-deficient fit may be misleading
pred_pops %>%
  ggplot(aes(x=year, y=pred, colour=age)) +
  geom_line() +
  geom_point() +
  facet_grid(sex~.) +
  scale_y_continuous(labels = comma, limits = c(0, 125000))


#How well do they match up with our overall populations?
pred_pops %>%
  group_by(year) %>%
  summarise(sum_pred_pop = sum(pred)) %>%
  right_join(overall_pops) %>%
  select(year, sum_pred_pop, population_without_inst_ship, total_population) %>%
  pivot_longer(cols = c(sum_pred_pop, population_without_inst_ship, total_population)) %>%
  ggplot(aes(x=year, y=value, colour=name)) +
  geom_point() +
  scale_y_continuous(labels = comma, limits = c(800000, 1250000))
Joining with `by = join_by(year)`

pred_pops %>%
  group_by(year, sex) %>%
  summarise(sum = sum(pred)) %>%
  group_by(year) %>%
  mutate(sex_ratio = first(sum)/last(sum))
`summarise()` has grouped output by 'year'. You can override using the `.groups` argument.

Population pyramids


label_abs <- function(x) {
  comma(abs(x))
}


pred_pops %>%
  ungroup() %>%
  group_by(year) %>%
  mutate(year_pop = sum(pred),
         age_sex_pct = percent(pred/year_pop, accuracy=0.1)) %>%
  mutate(sex = case_when(sex=="male" ~ "Male",
                         sex=="female" ~ "Female")) %>%
  ggplot(
    aes(x = age, fill = sex, 
        y = ifelse(test = sex == "Female",yes = -pred, no = pred))) + 
  geom_bar(stat = "identity") +
  geom_text(aes(label = age_sex_pct),
            position= position_stack(vjust=0.5), colour="white", size=2.5) +
  facet_wrap(year~., ncol=7) +
  coord_flip() +
  scale_y_continuous(labels = label_abs) +
  scale_fill_manual(values = c("mediumseagreen", "purple"), name="") +
  theme_ggdist() +
  theme(axis.text.x = element_text(angle=90, hjust = 1, vjust=0.5),
        legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  labs(x="", y="") 


ggsave(here("figures/s2.png"), width=10)
Saving 10 x 4.51 in image

Not perfect, but resonably good. But ahhhhh… the age groups don’t align with the case notification age groups! Come back to think about this later.

4. Tuberculosis cases

Import the tuberculosis cases dataset

4.1 Overall notifications

Overall, by year.


cases_by_year <- read_xlsx("2023-11-28_glasgow-acf.xlsx", sheet = "by_year")

cases_by_year%>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()


#shift year to midpoint
cases_by_year <- cases_by_year %>%
  mutate(year2 = year+0.5)

Plot the overall number of case notified per year, by pulmonary and extra pulmonary classification.


cases_by_year %>%
  select(-total_notifications, -year) %>%
  pivot_longer(cols = c(pulmonary_notifications, `non-pulmonary_notifications`)) %>%
  mutate(name = case_when(name == "pulmonary_notifications" ~ "Pulmonary TB",
                          name == "non-pulmonary_notifications" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=value, x=year2, group = name, fill=name), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA

4.2 Notifications by Division

Read in the datasets and merge together.


#list all the sheets
all_sheets <- excel_sheets("2023-11-28_glasgow-acf.xlsx")

#get the ward sheets
ward_sheets <- enframe(all_sheets) %>%
  filter(grepl("by_ward", value)) %>%
  pull(value)


cases_by_ward_sex_year <- map_df(ward_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

cases_by_ward_sex_year %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA

Aggregate together to case cases by division


cases_by_division <- cases_by_ward_sex_year %>%
  left_join(ward_lookup) %>%
  group_by(division, year, tb_type) %>%
  summarise(cases = sum(cases, na.rm = TRUE))
Joining with `by = join_by(ward)``summarise()` has grouped output by 'division', 'year'. You can override using the `.groups` argument.
#shift year to midpoint
cases_by_division <- cases_by_division %>%
  mutate(year2 = year+0.5) %>%
  ungroup()

cases_by_division  %>%
  select(-year2) %>%
  select(year, everything()) %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()


cases_by_division %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=cases, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(division~., scales = "free_y") +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications by Division",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

4.3 Notifications by ward



cases_by_ward <- cases_by_ward_sex_year %>%
  group_by(ward, year, tb_type) %>%
  summarise(cases = sum(cases, na.rm = TRUE)) %>%
  ungroup()
`summarise()` has grouped output by 'ward', 'year'. You can override using the `.groups` argument.
cases_by_ward %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  select(year, everything()) %>%
  datatable()

#shift year to midpoint
cases_by_ward <- cases_by_ward %>%
  mutate(year2 = year+0.5)

cases_by_ward %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=cases, x=year2, group = tb_type, fill=tb_type), alpha=0.8) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(ward~., scales = "free_y") +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications by Ward",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme(legend.position = "bottom")

NA
NA

4.4 Notifications by age and sex

As we don’t have denominators, we will just model the change in counts.


#list all the sheets
all_sheets <- excel_sheets("2023-11-28_glasgow-acf.xlsx")

#get the ward sheets
age_sex_sheets <- enframe(all_sheets) %>%
  filter(grepl("by_age_sex", value)) %>%
  pull(value)


cases_by_age_sex <- map_df(age_sex_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

cases_by_age_sex %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA
NA

5 TB incidence

5.1 Overall TB incidence

Now calculate incidence per 100,000 population

Merge the notification and population denominator datasets together.

Here we need to include the whole population (with shipping and institutions) as they are included in the notifications.


overall_inc <- overall_pops %>%
  left_join(cases_by_year)
Joining with `by = join_by(year, year2)`
overall_inc <- overall_inc %>%
  mutate(inc_pulm_100k = pulmonary_notifications/total_population*100000,
         inc_ep_100k = `non-pulmonary_notifications`/total_population*100000,
         inc_100k = total_notifications/total_population*100000)

overall_inc %>%
  select(year, inc_100k, inc_pulm_100k, inc_ep_100k) %>%
  mutate_at(.vars = vars(inc_100k, inc_pulm_100k, inc_ep_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

overall_inc %>%
  select(year2, inc_pulm_100k, inc_ep_100k) %>%
  pivot_longer(cols = c(inc_pulm_100k, `inc_ep_100k`)) %>%
  mutate(name = case_when(name == "inc_pulm_100k" ~ "Pulmonary TB",
                          name == "inc_ep_100k" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=value, x=year2, group = name, fill=name), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Case notification rate (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA
NA

5.2 TB incidence by Division


division_inc <- division_pops %>%
  left_join(cases_by_division)
Joining with `by = join_by(division, year)`
division_inc <- division_inc %>%
  mutate(inc_100k = cases/total_population*100000)

division_inc %>%
  select(year, division, tb_type, inc_100k) %>%
  mutate_at(.vars = vars(inc_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

division_inc %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=inc_100k, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(division~.) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate, by Division",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Case notification rate (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA
NA

5.2 TB incidence by Ward

Here we will filter out the institutions and harbour from the denominators, as we don’t have reliable population denominators for them.


ward_inc <- ward_pops %>%
  left_join(cases_by_ward)
Joining with `by = join_by(ward, year, year2)`
ward_inc <- ward_inc %>%
  mutate(inc_100k = cases/population_without_inst_ship*100000)

ward_inc %>%
  select(year, ward, tb_type, inc_100k) %>%
  mutate_at(.vars = vars(inc_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

ward_inc %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=inc_100k, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(ward~.) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate, by Ward",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Incidence (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme(legend.position = "bottom")

NA
NA
NA
NA

On a map


st_as_sf(left_join(ward_inc, glasgow_wards_1951)) %>%
  filter(tb_type=="Pulmonary") %>%
  ggplot() +
  geom_sf(aes(fill=inc_100k)) +
  facet_wrap(year~., ncol = 7) +
  scale_fill_viridis_c(name="Case notification rate (per 100,000)",
                       option = "A") +
  theme_ggdist() +
  theme(legend.position = "top",
        legend.key.width = unit(2, "cm"),
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  guides(fill=guide_colorbar(title.position = "top"))
Joining with `by = join_by(division, ward, ward_number)`

6. TB Mortality

6.1 Overall Mortality

Import the TB mortality data.

First, overall deaths. Note that in the original reports, we have a pulmonary TB death rate per million for all years, and numbers of pulmonary TB deaths for each year apart from 1950.


#get the overall mortality sheets
deaths_sheets <- enframe(all_sheets) %>%
  filter(grepl("deaths", value)) %>%
  pull(value)


overall_deaths <- map_df(deaths_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

overall_deaths %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA
NA
NA

Plot the raw numbers of pulmonary deaths


overall_deaths %>%
  ggplot(aes(x=year, y=pulmonary_deaths)) +
  geom_line(colour = "#DE0D92") +
  geom_point(colour = "#DE0D92") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  labs(y="Pulmonary TB deaths per year",
       x = "Year",
       title = "Numbers of pulmonary TB deaths",
       subtitle = "Glasgow, 1950-1963",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: no data for 1950") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

NA
NA

Now the incidence of pulmonary TB death

overall_deaths %>%
  ggplot(aes(x=year, y=pulmonary_death_rate_per_100k)) +
  geom_line(colour = "#4D6CFA") +
  geom_point(colour = "#4D6CFA") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(y="Annual incidence of death (per 100,000)",
       x = "Year",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

ggsave(here("figures/s7.png"), width=10)
Saving 10 x 4.51 in image

6. Table 1

Make Table 1 here, and save for publication.


overall_pops %>% 
  select(year, total_population) %>%
  left_join(overall_inc %>%
              select(year, 
                     pulmonary_notifications, inc_pulm_100k,
                     `non-pulmonary_notifications`, inc_ep_100k,
                     total_notifications, inc_100k)) %>%
  left_join(overall_deaths %>%
              select(year,
                     pulmonary_deaths, pulmonary_death_rate_per_100k)) %>%
  mutate(across(where(is.numeric) & !(year),  ~round(., digits=1))) %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) 
Joining with `by = join_by(year)`Joining with `by = join_by(year)`

7. Overall pulmonary TB model

7.1 FIt the model and priors

First model will investigate the impact of mass miniature X-ray campaign on pulmonary TB case notification rate using an interrupted time series analysis.

Set up the data


mdata1 <- overall_inc %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  mutate(y_num = 1:nrow(.)) %>%
  rename(extrapulmonary_notifications = `non-pulmonary_notifications`)

Work on the priors a bit

Basic prior


basic_prior <- c(prior(normal(0, 1), class = Intercept),
                 prior(normal(0, 0.25), class = b))

Look at the mean and variance of counts (counts of pulmonary notifications are what we are predicting)


#Mean of counts per year
mean(mdata1$pulmonary_notifications)
[1] 1858.429
#variance of counts per year
var(mdata1$pulmonary_notifications)
[1] 716579.8

Quite a bit of over-dispersion here, so negative binomial distribution might be a better choice of distributional family than Poisson.

Slightly more informative prior (“weakly informative” really)


ggplot(data = tibble(x = seq(from = 500, to = 5000, by = 10)),
       aes(x = x, y = dgamma(x, shape = 0.1, rate = 0.00001))) +
  geom_area(color = "transparent", 
            fill = "#DE0D92") +
  scale_x_continuous(NULL) +
  coord_cartesian(xlim = c(500, 5000)) +
  ggtitle(expression(brms~~gamma(0.1*", "*0.00001)~shape~prior))

NA
NA

Fit a model with only priors


winform_prior <- c(prior(normal(0, 1), class = Intercept),
                  prior(gamma(0.1, 0.00001), class = shape),
                  prior(normal(0, 0.25), class = b))


m_pulmonary_prior <- brm(
  pulmonary_notifications ~ y_num + acf_period + acf_period:y_num +  offset(log(total_population)),
                  data = mdata1,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = winform_prior,
                  sample_prior = "only",
                  backend="cmdstanr",
                  save_pars = save_pars(all = TRUE),
                  warmup = 1000)
Compiling Stan program...

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\
In file included from /var/folders/bh/wr0g5x9j2wq46p9hm3ft_b380000gn/T/RtmpNIC2tD/model-a5fb6c6e21dc.hpp:1:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/src/stan/model/model_header.hpp:4:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math.hpp:19:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev.hpp:10:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev/fun.hpp:198:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor.hpp:15:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/integrate_ode_rk45.hpp:6:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/ode_rk45.hpp:9:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint.hpp:76:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint/integrate/observer_collection.hpp:23:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function.hpp:30:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/detail/prologue.hpp:17:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/function_base.hpp:21:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index.hpp:29:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index/stl_type_index.hpp:47:
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0

|
/boost/container_hash/hash.hpp:132:33: warning: 'unary_function<const std::error_category *, unsigned long>' is deprecated [-Wdeprecated-declarations]

/
        struct hash_base : std::unary_function<T, std::size_t> {};
                                ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:692:18: note: in instantiation of template class 'boost::hash_detail::hash_base<const std::error_category *>' requested here
        : public boost::hash_detail::hash_base<T*>
                 ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:420:24: note: in instantiation of template class 'boost::hash<const std::error_category *>' requested here
        boost::hash<T> hasher;
                       ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:551:9: note: in instantiation of function template specialization 'boost::hash_combine<const std::error_category *>' requested here
        hash_combine(seed, &v.category());
        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__functional/unary_function.h:23:29: note: 'unary_function<const std::error_category *, unsigned long>' has been explicitly marked deprecated here
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 unary_function
                            ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:850:41: note: expanded from macro '_LIBCPP_DEPRECATED_IN_CXX11'
#    define _LIBCPP_DEPRECATED_IN_CXX11 _LIBCPP_DEPRECATED
                                        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:835:49: note: expanded from macro '_LIBCPP_DEPRECATED'
#      define _LIBCPP_DEPRECATED __attribute__((deprecated))
                                                ^

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/
1 warning generated.

-

\
ld: warning: duplicate -rpath '/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/tbb' ignored

|

/

-

 
Start sampling
Running MCMC with 4 parallel chains...

Chain 1 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 1 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 1 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 1 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 1 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 1 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 1 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 1 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 1 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 1 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 1 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 1 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 1 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 1 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 1 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 1 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 1 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 1 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 1 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 1 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 1 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 1 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 2 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 2 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 2 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 2 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 2 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 2 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 2 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 2 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 2 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 2 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 2 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 2 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 2 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 2 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 2 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 2 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 2 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 2 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 2 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 2 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 2 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 2 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 3 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 3 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 3 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 3 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 3 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 3 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 3 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 3 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 3 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 3 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 3 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 3 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 3 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 3 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 3 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 3 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 3 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 3 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 3 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 3 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 3 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 4 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 4 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 4 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 4 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 4 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 4 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 4 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 4 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 4 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 4 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 4 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 4 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 4 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 4 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 4 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 4 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 4 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 4 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 4 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 4 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 4 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 4 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 1 finished in 0.1 seconds.
Chain 2 finished in 0.0 seconds.
Chain 3 finished in 0.1 seconds.
Chain 4 finished in 0.1 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.1 seconds.
Total execution time: 0.9 seconds.
Warning: 86 of 4000 (2.0%) transitions ended with a divergence.
See https://mc-stan.org/misc/warnings for details.
summary(m_pulmonary_prior)
Warning: There were 86 divergent transitions after warmup. Increasing adapt_delta above 0.8 may help. See http://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmup
 Family: negbinomial 
  Links: mu = log; shape = identity 
Formula: pulmonary_notifications ~ y_num + acf_period + acf_period:y_num + offset(log(total_population)) 
   Data: mdata1 (Number of observations: 14) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Population-Level Effects: 
                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                     -0.05      2.48    -5.09     4.62 1.00     2538     2031
y_num                          0.00      0.25    -0.50     0.48 1.00     2589     2402
acf_periodb.acf                0.00      0.25    -0.49     0.48 1.00     2908     1869
acf_periodc.postMacf           0.01      0.25    -0.48     0.49 1.00     2668     2293
y_num:acf_periodb.acf         -0.00      0.25    -0.49     0.46 1.00     2714     2401
y_num:acf_periodc.postMacf     0.00      0.26    -0.51     0.54 1.00     2137     1486

Family Specific Parameters: 
      Estimate Est.Error l-95% CI  u-95% CI Rhat Bulk_ESS Tail_ESS
shape 11729.33  36453.14     0.00 104278.62 1.01      937      801

Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
conditional_effects(m_pulmonary_prior)

Now fit the model with the weakly informative priors

m_pulmonary_overall <- brm(
  pulmonary_notifications ~ y_num + acf_period + acf_period:y_num +  offset(log(total_population)),
                  data = mdata1,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = winform_prior,
                  save_pars = save_pars(all = TRUE),
                  backend = "cmdstanr",
                  warmup = 1000)
Compiling Stan program...

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/
In file included from /var/folders/bh/wr0g5x9j2wq46p9hm3ft_b380000gn/T/RtmpNIC2tD/model-a5fb46ef9c1b.hpp:1:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/src/stan/model/model_header.hpp:4:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math.hpp:19:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev.hpp:10:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev/fun.hpp:198:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor.hpp:15:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/integrate_ode_rk45.hpp:6:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/ode_rk45.hpp:9:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint.hpp:76:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint/integrate/observer_collection.hpp:23:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function.hpp:30:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/detail/prologue.hpp:17:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/function_base.hpp:21:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index.hpp:29:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index/stl_type_index.hpp:47:
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0

-
/boost/container_hash/hash.hpp:132:33: warning: 'unary_function<const std::error_category *, unsigned long>' is deprecated [-Wdeprecated-declarations]
        struct hash_base : std::unary_function<T, std::size_t> {};
                                ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:692:18: note: in instantiation of template class 'boost::hash_detail::hash_base<const std::error_category *>' requested here
        : public boost::hash_detail::hash_base<T*>
                 ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:420:24: note: in instantiation of template class 'boost::hash<const std::error_category *>' requested here
        boost::hash<T> hasher;
                       ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:551:9: note: in instantiation of function template specialization 'boost::hash_combine<const std::error_category *>' requested here
        hash_combine(seed, &v.category());
        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__functional/unary_function.h:23:29: note: 'unary_function<const std::error_category *, unsigned long>' has been explicitly marked deprecated here
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 unary_function
                            ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:850:41: note: expanded from macro '_LIBCPP_DEPRECATED_IN_CXX11'
#    define _LIBCPP_DEPRECATED_IN_CXX11 _LIBCPP_DEPRECATED
                                        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:835:49: note: expanded from macro '_LIBCPP_DEPRECATED'
#      define _LIBCPP_DEPRECATED __attribute__((deprecated))
                                                ^

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|
1 warning generated.

/

-
ld: warning: duplicate -rpath '/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/tbb' ignored

\

|

/

 
Start sampling
Running MCMC with 4 parallel chains...

Chain 1 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 1 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 1 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 1 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 1 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 1 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 1 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 1 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 1 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 1 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 1 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 1 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 1 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 1 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 1 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 1 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 1 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 1 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 1 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 1 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 1 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 1 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 2 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 2 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 2 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 2 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 2 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 2 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 2 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 2 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 2 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 2 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 2 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 2 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 2 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 2 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 2 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 2 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 2 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 2 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 2 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 2 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 2 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 2 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 3 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 3 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 3 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 3 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 3 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 3 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 3 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 3 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 3 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 3 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 3 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 3 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 3 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 4 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 4 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 4 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 4 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 4 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 4 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 4 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 4 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 1 finished in 0.5 seconds.
Chain 2 finished in 0.4 seconds.
Chain 3 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 3 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 3 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 3 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 3 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 3 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 3 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 4 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 4 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 4 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 4 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 4 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 4 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 4 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 4 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 3 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 finished in 0.5 seconds.
Chain 4 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 4 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 4 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 4 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 4 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 4 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 4 finished in 0.4 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.4 seconds.
Total execution time: 1.0 seconds.
summary(m_pulmonary_overall)
 Family: negbinomial 
  Links: mu = log; shape = identity 
Formula: pulmonary_notifications ~ y_num + acf_period + acf_period:y_num + offset(log(total_population)) 
   Data: mdata1 (Number of observations: 14) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Population-Level Effects: 
                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                     -6.10      0.03    -6.17    -6.04 1.00     2999     2234
y_num                         -0.02      0.01    -0.03    -0.01 1.00     2904     2266
acf_periodb.acf                0.02      0.25    -0.45     0.53 1.00     1764     2081
acf_periodc.postMacf           0.05      0.11    -0.19     0.26 1.00     1935     1892
y_num:acf_periodb.acf          0.08      0.03     0.01     0.14 1.00     1755     2160
y_num:acf_periodc.postMacf    -0.05      0.01    -0.08    -0.03 1.00     1821     1648

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
shape  4409.62  15136.27   322.80 26935.74 1.00     1318     1213

Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
plot(m_pulmonary_overall)

pp_check(m_pulmonary_overall, type='ecdf_overlay')
Using 10 posterior draws for ppc type 'ecdf_overlay' by default.

7.2 Summarise change in CNRs

Summarise the posterior


f1b <- plot_counterfactual(model_data = mdata1, model = m_pulmonary_overall, population_denominator = total_population, outcome = inc_pulm_100k, grouping_var=NULL)
  
f1b

Make this into a figure


f1a <- st_as_sf(left_join(ward_inc, glasgow_wards_1951)) %>%
  filter(tb_type=="Pulmonary") %>%
  ggplot() +
  geom_sf(aes(fill=inc_100k)) +
  facet_wrap(year~., ncol = 7) +
  scale_fill_viridis_c(name="Case notification rate (per 100,000)",
                       option = "A") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA),
        legend.position = "top",
        #legend.key.width = unit(2, "cm"),
        legend.title.align = 0.5) +
  guides(fill=guide_colorbar(title.position = "top"))
Joining with `by = join_by(division, ward, ward_number)`
(f1a / f1b) + plot_annotation(tag_levels = "A")

ggsave(here("figures/f1.png"))
Saving 7.29 x 4.51 in image

Summary of change in notifications


summarise_change(model_data=mdata1, model=m_pulmonary_overall, population_denominator=total_population, grouping_var=NULL) %>%
  map(datatable)
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
$immediate_change

$post_change

$slope_change
NA

(Alternative way - keep in for now)


overall_immediate_draws <- mdata1 %>%
  select(year, year2, y_num, acf_period, total_population, pulmonary_notifications) %>%
  filter(year %in% c(1956,1957)) %>%
  add_epred_draws(m_pulmonary_overall) %>%
  mutate(inc_100k = .epred/total_population*100000) %>%
  group_by(.draw) %>%
  summarise(pct_change_immediate = (last(inc_100k) - first(inc_100k))/first(inc_100k)) %>%
  ungroup()

overall_post_draws <- mdata1 %>%
  select(year, year2, y_num, acf_period, total_population, pulmonary_notifications) %>%
  filter(year %in% c(1956,1958)) %>%
  add_epred_draws(m_pulmonary_overall) %>%
  mutate(inc_100k = .epred/total_population*100000) %>%
  group_by(.draw) %>%
  summarise(pct_change_post = (last(inc_100k) - first(inc_100k))/first(inc_100k)) %>%
  ungroup()


overall_slope_draws <- mdata1 %>%
  select(year, year2, y_num, acf_period, total_population, pulmonary_notifications) %>%
  filter(year %in% c(1950, 1956, 1958, 1963)) %>%
  add_epred_draws(m_pulmonary_overall) %>%
  mutate(inc_100k = .epred/total_population*100000) %>%
  ungroup() %>%
  mutate(n_years = length(year), .by=acf_period) %>%
  group_by(acf_period, .draw) %>%
  summarise(pct_change_slope = ((last(inc_100k) - first(inc_100k))/first(inc_100k))/n_years) %>%
  distinct() %>%
  pivot_wider(names_from = c(acf_period),
              values_from = pct_change_slope) %>%
  mutate(ratio_annual_slope = `c. post-acf` / `a. pre-acf`)
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.`summarise()` has grouped output by 'acf_period', '.draw'. You can override using the `.groups` argument.

Correlation between immediate effect and post effect of ACF


left_join(overall_immediate_draws, overall_post_draws) %>%
  ggplot(aes(x=pct_change_immediate, y=pct_change_post)) +
  geom_hdr(
    aes(fill = after_stat(probs)), 
    alpha = 1) +
  #geom_hdr_points(aes(colour = after_stat(probs)), size=0.5) +
  geom_smooth(method = "lm", se=FALSE, colour="black", linewidth=0.5) +
  stat_regline_equation(label.x = 0.25, label.y = -0.25, size=4) +
  scale_x_continuous(labels = percent,
                     breaks = pretty_breaks(n = 10)) +
  scale_y_continuous(labels = percent,
                     breaks = pretty_breaks(n = 5)) +
  scale_fill_viridis_d(option="E", name="") +
  labs(title="Correlation between immediate ACF impact and post-ACF case notification rate",
       y="Post intervention impact: ercentage change in CNR (1958 vs. 1956)",
       x="Immediate impact: percentage change in CNR (1957 vs. 1956)",
       caption="Boundaries are posterior desnity intervals from 4000 draws") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))
Joining with `by = join_by(.draw)`

Correlation between immediate effect and change in slope


left_join(overall_immediate_draws, overall_slope_draws) %>%
  ggplot(aes(x=pct_change_immediate, y=ratio_annual_slope)) +
  geom_hdr(
    aes(fill = after_stat(probs)), 
    alpha = 1) +
  #geom_hdr_points(aes(colour = after_stat(probs)), size=0.5) +
  geom_smooth(method = "lm", se=FALSE, colour="black", linewidth=0.5) +
  #stat_regline_equation(label.x = 0.25, label.y = 0.02, size=4) +
  scale_x_continuous(labels = percent,
                     breaks = pretty_breaks(n = 10)) +
  scale_y_continuous(breaks = pretty_breaks(n = 5),
                     limits = c(0, 10)) +
  scale_fill_viridis_d(option="E", name="") +
  labs(title="Correlation between immediate ACF impact and post-ACF case notification rate",
       y="Post intervention impact: Percentage change in CNR (1958 vs. 1956)",
       x="Immediate impact: percentage change in CNR (1957 vs. 1956)",
       caption="Points are draws from posteior distribution") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))
Joining with `by = join_by(.draw)`

Another way


as_draws_df(m_pulmonary_overall)
# A draws_df: 1000 iterations, 4 chains, and 10 variables
# ... with 3990 more draws, and 2 more variables
# ... hidden reserved variables {'.chain', '.iteration', '.draw'}

7.3 Compared to counterfactual


overall_pulmonary_counterf <- calcuate_counterfactual(model_data = mdata1, model=m_pulmonary_overall, population_denominator = total_population)
Joining with `by = join_by(year, total_population, .draw)`
overall_pulmonary_counterf %>%
  map(datatable)
$counter_post
NA

Total pulmonary TB cases averted between 1958 and 1963


overall_pulmonary_counterf$counter_post %>%
  summarise(across(c(cases_averted, cases_averted.lower, cases_averted.upper), sum))
NA
NA

8. Extra-pulmonary TB notifications

8.1 Fit the


m_extrap_overall <- brm(
  extrapulmonary_notifications ~ y_num + acf_period + acf_period:y_num +offset(log(total_population)),
                  data = mdata1,
                  family = poisson(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = basic_prior,
                  save_pars = save_pars(all = TRUE),
                  backend = "cmdstanr",
                  warmup = 1000)

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

 
Running MCMC with 4 parallel chains...

Chain 1 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 1 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 1 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 1 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 1 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 1 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 1 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 1 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 1 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 1 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 1 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 1 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 1 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 1 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 1 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 1 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 1 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 1 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 1 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 1 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 1 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 1 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 2 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 2 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 2 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 2 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 2 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 2 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 2 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 2 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 2 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 2 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 2 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 2 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 2 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 2 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 2 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 2 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 2 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 2 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 2 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 2 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 2 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 2 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 3 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 3 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 3 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 3 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 3 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 3 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 3 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 3 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 3 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 3 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 3 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 3 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 3 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 3 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 3 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 3 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 3 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 3 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 3 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 3 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 3 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 4 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 4 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 4 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 4 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 4 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 4 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 4 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 4 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 4 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 4 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 4 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 4 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 4 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 4 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 4 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 4 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 4 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 4 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 4 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 4 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 4 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 4 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 1 finished in 0.2 seconds.
Chain 2 finished in 0.2 seconds.
Chain 3 finished in 0.2 seconds.
Chain 4 finished in 0.2 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.2 seconds.
Total execution time: 0.9 seconds.
summary(m_extrap_overall)
 Family: poisson 
  Links: mu = log 
Formula: extrapulmonary_notifications ~ y_num + acf_period + acf_period:y_num + offset(log(total_population)) 
   Data: mdata1 (Number of observations: 14) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Population-Level Effects: 
                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                     -7.90      0.05    -7.99    -7.81 1.00     2908     2532
y_num                         -0.09      0.01    -0.11    -0.07 1.00     2623     2183
acf_periodb.acf               -0.00      0.24    -0.48     0.48 1.00     2558     2487
acf_periodc.postMacf          -0.32      0.17    -0.64     0.01 1.00     2095     2415
y_num:acf_periodb.acf         -0.02      0.03    -0.08     0.04 1.00     2413     2577
y_num:acf_periodc.postMacf     0.02      0.02    -0.02     0.05 1.00     1711     2108

Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
plot(m_extrap_overall)

pp_check(m_extrap_overall, type='ecdf_overlay')

plot_counterfactual(model_data = mdata1, model=m_extrap_overall, population_denominator = total_population, outcome=inc_ep_100k)

  
ggsave(here("figures/s7.png"), width=10)
Saving 10 x 4.51 in image

8.2 Summary of change

A. Percentage change in mortality, from 1956 to 1957 (i.e. immediate ACF effect)


summarise_change(model_data=mdata1, model = m_extrap_overall, population_denominator = total_population) %>%
  map(datatable)
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
$immediate_change

$post_change

$slope_change
NA

8.3 Compared to counterfactual


overall_ep_counterf <- calcuate_counterfactual(model_data = mdata1, model=m_extrap_overall, population_denominator = total_population)
Joining with `by = join_by(year, total_population, .draw)`
overall_ep_counterf %>%
  map(datatable)
$counter_post
NA

Total extra pulmonary TB cases averted between 1958 and 1963


overall_ep_counterf $counter_post %>%
  summarise(across(c(cases_averted, cases_averted.lower, cases_averted.upper), sum))
NA
NA

9. Ward level model

9.1 Fit the model


mdata2 <- ward_inc %>%
  filter(tb_type=="Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  group_by(ward) %>%
  mutate(y_num = row_number()) %>%
  ungroup()

(Note the denominator without institutionalised people and “shipping”!)

#weakly informative priors for multilevel model
basic_prior2 <- c(prior(normal(0, 1), class = Intercept),
                 prior(normal(0, 0.1), class = b),
                 prior(cauchy(0,5), class="sd"))


ggplot(data = tibble(x = seq(from = 0, to = 250, by = 10)),
       aes(x = x, y = dgamma(x, shape = 0.5, rate = 0.01))) +
  geom_area(color = "transparent", 
            fill = "#DE0D92") +
  scale_x_continuous(NULL) +
  scale_y_continuous(NULL, breaks = NULL) +
  coord_cartesian(xlim = c(0, 250)) +
  ggtitle(expression(brms~~gamma(0.5*", "*0.00001)~shape~prior))


winform_prior2 <- c(prior(normal(0, 1), class = Intercept),
                  prior(gamma(0.5, 0.01), class = shape),
                  prior(normal(0, 1), class = b),
                  prior(cauchy(0,5), class="sd"),
                  prior(lkj(2), class="cor"))

m_pulmonary_ward_prior <- brm(
  cases ~ y_num + acf_period + acf_period:y_num + (1 + y_num + acf_period + acf_period:y_num | ward) + offset(log(population_without_inst_ship)),
                  data = mdata2,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = winform_prior2,
                  save_pars = save_pars(all = TRUE),
                  sample_prior = "only",
                  backend = "cmdstanr",
                  warmup = 1000)
Compiling Stan program...

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-
In file included from /var/folders/bh/wr0g5x9j2wq46p9hm3ft_b380000gn/T/RtmpNIC2tD/model-a5fb62d79c.hpp:1:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/src/stan/model/model_header.hpp:4:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math.hpp:19:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev.hpp:10:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev/fun.hpp:198:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor.hpp:15:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/integrate_ode_rk45.hpp:6:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/ode_rk45.hpp:9:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint.hpp:76:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint/integrate/observer_collection.hpp:23:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function.hpp:30:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/detail/prologue.hpp:17:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/function_base.hpp:21:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index.hpp:29:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index/stl_type_index.hpp:47:
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/b

\
oost/container_hash/hash.hpp:132:33: warning: 'unary_function<const std::error_category *, unsigned long>' is deprecated [-Wdeprecated-declarations]
        struct hash_base : std::unary_function<T, std::size_t> {};
                                ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:692:18: note: in instantiation of template class 'boost::hash_detail::hash_base<const std::error_category *>' requested here
        : public boost::hash_detail::hash_base<T*>
                 ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:420:24: note: in instantiation of template class 'boost::hash<const std::error_category *>' requested here
        boost::hash<T> hasher;
                       ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:551:9: note: in instantiation of function template specialization 'boost::hash_combine<const std::error_category *>' requested here
        hash_combine(seed, &v.category());
        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__functional/unary_function.h:23:29: note: 'unary_function<const std::error_category *, unsigned long>' has been explicitly marked deprecated here
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 unary_function
                            ^

|
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:850:41: note: expanded from macro '_LIBCPP_DEPRECATED_IN_CXX11'
#    define _LIBCPP_DEPRECATED_IN_CXX11 _LIBCPP_DEPRECATED
                                        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:835:49: note: expanded from macro '_LIBCPP_DEPRECATED'
#      define _LIBCPP_DEPRECATED __attribute__((deprecated))
                                                ^

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/
1 warning generated.

-

\
ld: warning: duplicate -rpath '/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/tbb' ignored

|

/

-

 
Start sampling
Running MCMC with 4 parallel chains...

Chain 1 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 1 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 1 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 1 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 1 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 1 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 1 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 1 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 1 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 1 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 1 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 1 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 1 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 1 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 1 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 1 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 1 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 2 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 2 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 2 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 2 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 2 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 2 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 2 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 2 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 2 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 2 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 2 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 2 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 2 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 2 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 2 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 3 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 3 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 3 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 3 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 3 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 3 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 3 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 3 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 3 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 3 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 3 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 3 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 3 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 4 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 4 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 4 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 4 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 4 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 4 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 4 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 4 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 4 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 1 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 1 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 1 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 1 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 2 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 2 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 2 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 3 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 3 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 3 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 4 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 4 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 4 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 4 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 1 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 1 finished in 0.8 seconds.
Chain 2 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 2 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 2 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 3 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 3 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 4 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 4 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 2 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 3 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 4 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 4 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 4 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 2 finished in 0.8 seconds.
Chain 3 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 3 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 4 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 4 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 3 finished in 0.8 seconds.
Chain 4 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 4 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 4 finished in 0.8 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.8 seconds.
Total execution time: 1.4 seconds.
conditional_effects(m_pulmonary_ward_prior)

NA
NA

Now fit the model with data

m_pulmonary_ward <- brm(
  cases ~ y_num + acf_period + acf_period:y_num + (1 + y_num + acf_period + acf_period:y_num | ward) + offset(log(population_without_inst_ship)),
                  data = mdata2,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = winform_prior2,
                  backend = "cmdstanr")
Compiling Stan program...

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-
In file included from /var/folders/bh/wr0g5x9j2wq46p9hm3ft_b380000gn/T/RtmpNIC2tD/model-a5fb161ed07f.hpp:1:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/src/stan/model/model_header.hpp:4:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math.hpp:19:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev.hpp:10:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev/fun.hpp:198:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor.hpp:15:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/integrate_ode_rk45.hpp:6:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/ode_rk45.hpp:9:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint.hpp:76:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint/integrate/observer_collection.hpp:23:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function.hpp:30:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/detail/prologue.hpp:17:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/function_base.hpp:21:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index.hpp:29:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index/stl_type_index.hpp:47:
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0

\
/boost/container_hash/hash.hpp:132:33: warning: 'unary_function<const std::error_category *, unsigned long>' is deprecated [-Wdeprecated-declarations]
        struct hash_base : std::unary_function<T, std::size_t> {};
                                ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:692:18: note: in instantiation of template class 'boost::hash_detail::hash_base<const std::error_category *>' requested here
        : public boost::hash_detail::hash_base<T*>
                 ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:420:24: note: in instantiation of template class 'boost::hash<const std::error_category *>' requested here
        boost::hash<T> hasher;
                       ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:551:9: note: in instantiation of function template specialization 'boost::hash_combine<const std::error_category *>' requested here
        hash_combine(seed, &v.category());
        ^

|
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__functional/unary_function.h:23:29: note: 'unary_function<const std::error_category *, unsigned long>' has been explicitly marked deprecated here
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 unary_function
                            ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:850:41: note: expanded from macro '_LIBCPP_DEPRECATED_IN_CXX11'
#    define _LIBCPP_DEPRECATED_IN_CXX11 _LIBCPP_DEPRECATED
                                        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:835:49: note: expanded from macro '_LIBCPP_DEPRECATED'
#      define _LIBCPP_DEPRECATED __attribute__((deprecated))
                                                ^

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-
1 warning generated.

\

|
ld: warning: duplicate -rpath '/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/tbb' ignored

/

-

\

 
Start sampling
Running MCMC with 4 parallel chains...

Chain 1 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 2 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 3 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 4 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 2 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 3 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 4 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 1 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 2 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 1 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 3 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 4 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 2 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 1 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 3 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 4 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 2 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 1 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 3 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 4 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 2 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 1 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 3 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 4 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 2 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 1 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 3 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 4 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 2 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 3 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 1 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 4 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 2 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 3 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 4 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 1 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 2 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 3 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 4 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 1 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 2 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 2 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 3 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 4 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 3 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 4 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 1 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 1 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 2 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 3 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 4 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 1 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 2 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 3 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 4 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 1 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 2 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 3 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 4 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 1 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 2 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 3 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 4 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 1 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 2 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 3 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 4 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 1 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 2 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 3 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 4 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 1 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 2 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 3 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 4 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 1 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 2 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 3 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 4 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 1 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 2 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 3 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 4 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 1 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 2 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 2 finished in 77.4 seconds.
Chain 3 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 finished in 79.0 seconds.
Chain 4 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 4 finished in 79.1 seconds.
Chain 1 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 1 finished in 80.6 seconds.

All 4 chains finished successfully.
Mean chain execution time: 79.0 seconds.
Total execution time: 80.9 seconds.
summary(m_pulmonary_ward)
 Family: negbinomial 
  Links: mu = log; shape = identity 
Formula: cases ~ y_num + acf_period + acf_period:y_num + (1 + y_num + acf_period + acf_period:y_num | ward) + offset(log(population_without_inst_ship)) 
   Data: mdata2 (Number of observations: 518) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Group-Level Effects: 
~ward (Number of levels: 37) 
                                                      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept)                                             0.26      0.04     0.20     0.34 1.00     1698     2316
sd(y_num)                                                 0.02      0.01     0.01     0.03 1.01     1217      978
sd(acf_periodb.acf)                                       0.08      0.05     0.00     0.18 1.00     1573     2064
sd(acf_periodc.postMacf)                                  0.13      0.08     0.01     0.30 1.00      939     1471
sd(y_num:acf_periodb.acf)                                 0.01      0.01     0.00     0.02 1.00     1612     2176
sd(y_num:acf_periodc.postMacf)                            0.01      0.01     0.00     0.03 1.01      576     1121
cor(Intercept,y_num)                                     -0.51      0.20    -0.81    -0.04 1.00     2566     2373
cor(Intercept,acf_periodb.acf)                           -0.28      0.33    -0.80     0.43 1.00     2987     2293
cor(y_num,acf_periodb.acf)                               -0.06      0.32    -0.64     0.58 1.00     5536     3410
cor(Intercept,acf_periodc.postMacf)                      -0.18      0.28    -0.67     0.41 1.00     4468     3115
cor(y_num,acf_periodc.postMacf)                           0.14      0.30    -0.45     0.70 1.00     3192     3324
cor(acf_periodb.acf,acf_periodc.postMacf)                 0.10      0.32    -0.54     0.69 1.00     1909     2968
cor(Intercept,y_num:acf_periodb.acf)                     -0.27      0.33    -0.79     0.45 1.00     3493     2858
cor(y_num,y_num:acf_periodb.acf)                         -0.07      0.32    -0.66     0.57 1.00     5401     3217
cor(acf_periodb.acf,y_num:acf_periodb.acf)               -0.09      0.34    -0.71     0.56 1.00     3930     3316
cor(acf_periodc.postMacf,y_num:acf_periodb.acf)           0.07      0.33    -0.58     0.67 1.00     3674     3348
cor(Intercept,y_num:acf_periodc.postMacf)                 0.02      0.31    -0.58     0.61 1.00     4641     2858
cor(y_num,y_num:acf_periodc.postMacf)                    -0.10      0.33    -0.69     0.57 1.00     1930     2364
cor(acf_periodb.acf,y_num:acf_periodc.postMacf)           0.07      0.33    -0.58     0.65 1.00     2736     3112
cor(acf_periodc.postMacf,y_num:acf_periodc.postMacf)     -0.16      0.36    -0.81     0.55 1.00     1594     1728
cor(y_num:acf_periodb.acf,y_num:acf_periodc.postMacf)     0.07      0.33    -0.57     0.68 1.00     1848     2837

Population-Level Effects: 
                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                     -6.14      0.05    -6.24    -6.04 1.00     1155     1961
y_num                         -0.02      0.01    -0.03    -0.01 1.00     3100     3310
acf_periodb.acf                0.02      1.02    -1.99     1.98 1.00     4602     3119
acf_periodc.postMacf           0.05      0.11    -0.16     0.25 1.00     4476     2977
y_num:acf_periodb.acf          0.08      0.13    -0.16     0.33 1.00     4578     3148
y_num:acf_periodc.postMacf    -0.05      0.01    -0.07    -0.03 1.00     4216     3135

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
shape    98.15     23.53    63.84   158.13 1.00     3107     2818

Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
plot(m_pulmonary_ward)

pp_check(m_pulmonary_ward, type='ecdf_overlay')
Using 10 posterior draws for ppc type 'ecdf_overlay' by default.


plot_counterfactual(model_data = mdata2, model=m_pulmonary_ward, outcome = inc_100k, population_denominator = population_without_inst_ship, grouping_var = ward, ward)
  
ggsave(here("figures/s3.png"), width=10, height=12)

9.2 Summary of change

A. percentage increase in CNR, from 1956 to 1957 (i.e. immediate ACF effect)


ward_change <- summarise_change(model_data = mdata2, model = m_pulmonary_ward, population_denominator = population_without_inst_ship, grouping_var=ward) 
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
ward_change %>%
  map(datatable)
$immediate_change

$post_change

$slope_change
NA

As a supplementary figure

  
ward_change$immediate_change %>%
  arrange(acf_inc100k_rr) %>%
  ggplot() +
  geom_pointrange(aes(y=acf_inc100k_rr, ymin=acf_inc100k_rr.lower, ymax=acf_inc100k_rr.upper, 
                      x=fct_reorder(ward, acf_inc100k_rr),
                      colour = acf_inc100k_rr)) +
  geom_hline(aes(yintercept=1), linetype=2) +
  coord_flip() +
  scale_colour_viridis_b(option = "D") +
  scale_y_continuous(limits = c(0.8,3.0)) +
  labs(x="",
       y="Relative posterior predicted case notification rate (per 100,000; 95% UI)\nACF (1957) vs. Before ACF (1956)") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA))
  
ggsave(here("figures/s4.png"))
Saving 7.29 x 4.51 in image


ward_change$post_change %>%
  arrange(acf_inc100k_rr) %>%
  ggplot() +
  geom_pointrange(aes(y=acf_inc100k_rr, ymin=acf_inc100k_rr.lower, ymax=acf_inc100k_rr.upper, 
                      x=fct_reorder(ward, acf_inc100k_rr),
                      colour = acf_inc100k_rr)) +
  geom_hline(aes(yintercept=1), linetype=2) +
  coord_flip() +
  scale_colour_viridis_b(option = "D") +
  #scale_y_continuous(limits = c(0.8,3.0)) +
  labs(x="",
       y="Relative posterior predicted case notification rate (per 100,000; 95% UI)\nAfter ACF (1958) vs. Before ACF (1956)") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA))

ggsave(here("figures/s5.png"))
Saving 7.29 x 4.51 in image

percentage change = (final value - initial value) / initial value


ward_change$slope_change %>%
  ggplot() +
  geom_pointrange(aes(y=pct_change_epred_overall , ymin=pct_change_lower_overall , ymax=pct_change_upper_overall ,
                      group=acf_period, colour=acf_period,
                      x = fct_reorder(ward, pct_change_epred_overall ))) +
  coord_flip() +
  scale_y_continuous(labels =percent) +
  scale_colour_manual(values = c("#DE0D92", "#4D6CFA")) +
  #scale_y_continuous(limits = c(0.8,3.0)) +
  labs(title="Intervention effect of mass miniature chest X-ray in Glasgow",
       subtitle="By municipal ward",
       x="",
       y="Mean annual rate of change in case notification rate (95% CrI)\n Before ACF (1950-1956) vs. after ACF (1958-1963)") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

(Alternative figure - keep in for the minute)

Is there any correlation between immediate increase and a) post-intervention (1958) effect, and b) post intervention slope (1958-1963)


ward_cors <- ward_impact_out %>%
  select(ward, immediate_effect = acf_inc100k_rr,
               immediate_effect_lower = acf_inc100k_rr.lower,
               immediate_effect_upper = acf_inc100k_rr.upper) %>%
  right_join(
    ward_pulm_impact2 %>% 
      select(ward, post_effect = acf_inc100k_rr,
               post_effect_lower = acf_inc100k_rr.lower,
               post_effect_upper = acf_inc100k_rr.upper)
  ) %>%
  right_join(
    ward_pulm_impact3 %>%
      filter(acf_period=="c. post-acf") %>%
      select(ward, slope_effect = pct_change_epred_annual,
             slope_effect_lower = pct_change_lower_annual,
             slope_effect_upper = pct_change_upper_annual)
  )
Error in select(., ward, immediate_effect = acf_inc100k_rr, immediate_effect_lower = acf_inc100k_rr.lower,  : 
  object 'ward_impact_out' not found

Try a different way with the full distribution of posteriors

Correlation between immediate effect and post effect of ACF

Correlation between immediate effect and change in slope

Join these together with the overall estimates to make a single figure for showing impact

9.3 Compared to counterfactual

ward_counterf %>%
  map(datatable)
$counter_post
NA

Total pulmonary TB cases averted between 1958 and 1963

10. Age-sex model

Fit the model

(Not rewritten the functions for this yet)

Summarise posterior

Summary of impact of intervention

  1. percentage increase in CNR, from 1956 to 1957 (i.e. immediate ACF effect)
  1. Change from pre-ACF period (1956), to first year post-ACF (1958)
  1. Change in slope (i.e. difference in mean annual case notification rate pre-Intervention vs. post-intervention, by ward)

Join together for Figure 2.

Is there any correlation between immediate increase and a) post-intervention (1958) effect, and b) post intervention slope (1958-1963)

11. Division-level model

(Very much a work in progress!)

LS0tCnRpdGxlOiAiR2xhc2dvdyBUQiBBQ0YiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIyAxLiBMaWJyYXJpZXMgYW5kIGZ1bmN0aW9ucwoKIyMjIyAxLjEgTGlicmFyaWVzCgpMb2FkIHRoZSByZXF1aXJlZCBsaWJyYXJpZXMuCgpgYGB7ciwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShEVCkKbGlicmFyeShicm1zKQpsaWJyYXJ5KHRpZHliYXllcykKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkobWFyZ2luYWxlZmZlY3RzKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoc2NpY28pCmxpYnJhcnkoZ2dkZW5zaXR5KQpsaWJyYXJ5KGdncHVicikKCmBgYAoKIyMjIyAxLjIgSGVscGVyIGZ1bmN0aW9ucwoKRnVuY3Rpb25zIHRoYXQgd2Ugd2lsbCB1c2UgdGhyb3VnaG91dCB0aGUgc2NyaXB0CgpgYGB7cn0KI2xhYmVsbGVyIGZvciB5ZWFycwp5ZWFyX2xhYmVscyA8LSBjKDE5NTA6MTk2MykKCiNUaGUgR2xhc2dvdyBtYXNzIG1pbnV0dXJlIGNoZXN0IFgtcmF5IGNhbXBhaWduIGhhcHBlbmVkIGJldHdlZW4gMTF0aCBNYXJjaCBhbmQgMTJ0aCBBcHJpbCAxOTU3CiNTZWdtZW50IGZvciBncmFwaHMgdG8gbWF0Y2ggQUNGIHBlcmlvZAphY2Zfc3RhcnQgPC0gZGVjaW1hbF9kYXRlKHltZCgiMTk1Ny0wMy0xMSIpKQphY2ZfZW5kIDwtIGRlY2ltYWxfZGF0ZSh5bWQoIjE5NTctMDQtMTIiKSkKCgpgYGAKCkZ1bmN0aW9uIGZvciBjb3VudGVyZmFjdHVhbCBwbG90cwoKYGBge3J9CgpwbG90X2NvdW50ZXJmYWN0dWFsIDwtIGZ1bmN0aW9uKG1vZGVsX2RhdGEsIG1vZGVsLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yLCBvdXRjb21lLCBncm91cGluZ192YXI9TlVMTCwgLi4uKXsKICAKICAjbGFiZWxsZXIgZm9yIHllYXJzCiAgeWVhcl9sYWJlbHMgPC0gYygxOTUwOjE5NjMpCgogICNUaGUgR2xhc2dvdyBtYXNzIG1pbnV0dXJlIGNoZXN0IFgtcmF5IGNhbXBhaWduIGhhcHBlbmVkIGJldHdlZW4gMTF0aCBNYXJjaCBhbmQgMTJ0aCBBcHJpbCAxOTU3CiAgI1NlZ21lbnQgZm9yIGdyYXBocyB0byBtYXRjaCBBQ0YgcGVyaW9kCiAgYWNmX3N0YXJ0IDwtIGRlY2ltYWxfZGF0ZSh5bWQoIjE5NTctMDMtMTEiKSkKICBhY2ZfZW5kIDwtIGRlY2ltYWxfZGF0ZSh5bWQoIjE5NTctMDQtMTIiKSkKCiAgc3VtbWFyeSA8LSB7e21vZGVsX2RhdGF9fSAlPiUKICAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QsIHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB7e291dGNvbWV9fSwge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICBhZGRfZXByZWRfZHJhd3Moe3ttb2RlbH19KSAlPiUKICAgIGdyb3VwX2J5KHllYXIyLCBhY2ZfcGVyaW9kLCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgIG1lYW5fcWkoKSAlPiUKICAgIG11dGF0ZSguZXByZWRfaW5jID0gLmVwcmVkL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCwKICAgICAgICAgIC5lcHJlZF9pbmMubG93ZXIgPSAuZXByZWQubG93ZXIve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwLAogICAgICAgICAgLmVwcmVkX2luYy51cHBlciA9IC5lcHJlZC51cHBlci97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDApICU+JQogICAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oYWNmX3BlcmlvZD09ImEuIHByZS1hY2YiIH4gIkJlZm9yZSBJbnRlcnZlbnRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZD09ImMuIHBvc3QtYWNmIiB+ICJQb3N0IEludGVydmVudGlvbiIpKQoKCgogICNjcmVhdGUgdGhlIGNvdW50ZXJmYWN0dWFsIChubyBpbnRlcnZlbnRpb24pLCBhbmQgc3VtbWFyaXNlCiAgCiAgY291bnRlcmZhY3QgPC0KICAgIGFkZF9lcHJlZF9kcmF3cyhvYmplY3QgPSB7e21vZGVsfX0sCiAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IHt7bW9kZWxfZGF0YX19ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0sIHt7b3V0Y29tZX19KSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gImEuIHByZS1hY2YiKSkgJT4lCiAgICBncm91cF9ieSh5ZWFyMiwgYWNmX3BlcmlvZCwge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICBtZWFuX3FpKCkgJT4lCiAgICBtdXRhdGUoLmVwcmVkX2luYyA9IC5lcHJlZC97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDAsCiAgICAgICAgIC5lcHJlZF9pbmMubG93ZXIgPSAuZXByZWQubG93ZXIve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwLAogICAgICAgICAuZXByZWRfaW5jLnVwcGVyID0gLmVwcmVkLnVwcGVyL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCkgJT4lCiAgICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbihhY2ZfcGVyaW9kPT0iYS4gcHJlLWFjZiIgfiAiQmVmb3JlIEludGVydmVudGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZD09ImMuIHBvc3QtYWNmIiB+ICJQb3N0IEludGVydmVudGlvbiIpKQogIAoKCiAgI3Bsb3QgdGhlIGludGVydmVudGlvbiBlZmZlY3QKcCA8LSBzdW1tYXJ5ICU+JQogICAgZHJvcGxldmVscygpICU+JQogICAgZ2dwbG90KCkgKwogICAgZ2VvbV9yaWJib24oYWVzKHltaW49LmVwcmVkX2luYy5sb3dlciwgeW1heD0uZXByZWRfaW5jLnVwcGVyLCB4PXllYXIyLCBncm91cCA9IGFjZl9wZXJpb2QsIGZpbGw9YWNmX3BlcmlvZCksIGFscGhhPTAuNSkgKwogICAgZ2VvbV9yaWJib24oZGF0YSA9IGNvdW50ZXJmYWN0ICU+JSBmaWx0ZXIoeWVhcj49MTk1NiksIAogICAgICAgICAgICAgICAgYWVzKHltaW49LmVwcmVkX2luYy5sb3dlciwgeW1heD0uZXByZWRfaW5jLnVwcGVyLCB4PXllYXIyLCBmaWxsPSJDb3VudGVyZmFjdHVhbCIpLCBhbHBoYT0wLjUpICsKICAgIGdlb21fbGluZShkYXRhID0gY291bnRlcmZhY3QgJT4lIGZpbHRlcih5ZWFyPj0xOTU2KSwgCiAgICAgICAgICAgICAgYWVzKHk9LmVwcmVkX2luYywgeD15ZWFyMiwgY29sb3VyPSJDb3VudGVyZmFjdHVhbCIpKSArCiAgICBnZW9tX2xpbmUoYWVzKHk9LmVwcmVkX2luYywgeD15ZWFyMiwgZ3JvdXA9YWNmX3BlcmlvZCwgIGNvbG91cj1hY2ZfcGVyaW9kKSkgKwogICAgZ2VvbV9wb2ludChkYXRhID0ge3ttb2RlbF9kYXRhfX0sIGFlcyh5PXt7b3V0Y29tZX19LCB4PXllYXIyLCBzaGFwZT1hY2ZfcGVyaW9kKSwgc2l6ZT0yKSArCiAgICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgICB0aGVtZV9nZ2Rpc3QoKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNERTBEOTIiLCAiZ3JleTUwIiwgIiM0RDZDRkEiKSAsIG5hbWU9IiIpICsKICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiI0RFMEQ5MiIsICJncmV5NTAiLCAiIzRENkNGQSIpICwgbmFtZT0iIikgKwogICAgc2NhbGVfc2hhcGVfZGlzY3JldGUobmFtZT0iIikgKwogICAgbGFicygKICAgICAgeCA9ICJZZWFyIiwKICAgICAgeSA9ICJDYXNlIG5vdGlmaWNhdGlvbiByYXRlIChwZXIgMTAwLDAwMCkiLAogICAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICAgKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSksCiAgICAgICAgICB0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSwKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MTAsIGFuZ2xlID0gOTAsIGhqdXN0PTEsIHZqdXN0PTAuNSksCiAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkgKwogICAgZ3VpZGVzKHNoYXBlPSJub25lIikKCiAgICBmYWNldF92YXJzIDwtIHZhcnMoLi4uKQoKICBpZiAobGVuZ3RoKGZhY2V0X3ZhcnMpICE9IDApIHsKICAgIHAgPC0gcCArIGZhY2V0X3dyYXAoZmFjZXRfdmFycykKICB9CiAgcAoKfQoKYGBgCgpGdW5jdGlvbiBmb3IgY2FsY3VsYXRpbmcgIG1lYXN1cmVzIG9mIGNoYW5nZSBvdmVyIHRpbWUKCmBgYHtyfQoKc3VtbWFyaXNlX2NoYW5nZSA8LSBmdW5jdGlvbihtb2RlbF9kYXRhLCBtb2RlbCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciwgZ3JvdXBpbmdfdmFyPU5VTEwpewoKICAjYS4gaW1tZWRpYXRlIGNoYW5nZQogIG5kX2ltbWVkaWF0ZSA8LSB7e21vZGVsX2RhdGF9fSAlPiUKICAgIGZpbHRlcih5ZWFyICVpbiUgYygxOTU2OjE5NTcpKSAlPiUKICAgIHNlbGVjdChhY2ZfcGVyaW9kLCB5ZWFyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0pCgogICNDYWxjdWF0ZSBpbmNpZGVuY2UgcGVyIGRyYXcsIHRoZW4gc3VtbWFyaXNlLgogIGltbWVkaWF0ZV9jaGFuZ2UgPC0gYWRkX2VwcmVkX2RyYXdzKHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhPW5kX2ltbWVkaWF0ZSkgJT4lCiAgICBtdXRhdGUoZXByZWRfaW5jMTAwayA9IC5lcHJlZC97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSkgJT4lCiAgICBncm91cF9ieSguZHJhdywge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICBtdXRhdGUoYWNmX2luYzEwMGtfZGlmZiA9IGxhc3QoZXByZWRfaW5jMTAwayktZmlyc3QoZXByZWRfaW5jMTAwayksCiAgICAgICAgICAgYWNmX2luYzEwMGtfcnIgPSBsYXN0KGVwcmVkX2luYzEwMGspL2ZpcnN0KGVwcmVkX2luYzEwMGspKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIGdyb3VwX2J5KHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVhbl9xaShhY2ZfaW5jMTAwa19kaWZmLCBhY2ZfaW5jMTAwa19ycikgJT4lCiAgICBtdXRhdGUoY2hhbmdlID0gIkltbWVkaWF0ZSBjaGFuZ2UiKSAlPiUKICAgIHVuZ3JvdXAoKQogIAogICNiLiBwb3N0LUFDRiBjaGFuZ2UKICBuZF9wb3N0IDwtIHt7bW9kZWxfZGF0YX19ICU+JQogICAgZmlsdGVyKHllYXIgJWluJSBjKDE5NTYsMTk1OCkpICU+JQogICAgc2VsZWN0KGFjZl9wZXJpb2QsIHllYXIsIHlfbnVtLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSkKCiAgI0NhbGN1YXRlIGluY2lkZW5jZSBwZXIgZHJhdywgdGhlbiBzdW1tYXJpc2UuCiAgcG9zdF9jaGFuZ2UgPC0gYWRkX2VwcmVkX2RyYXdzKHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhPW5kX3Bvc3QpICU+JQogICAgbXV0YXRlKGVwcmVkX2luYzEwMGsgPSAuZXByZWQve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0pICU+JQogICAgZ3JvdXBfYnkoLmRyYXcsIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbXV0YXRlKGFjZl9pbmMxMDBrX2RpZmYgPSBsYXN0KGVwcmVkX2luYzEwMGspLWZpcnN0KGVwcmVkX2luYzEwMGspLAogICAgICAgICAgIGFjZl9pbmMxMDBrX3JyID0gbGFzdChlcHJlZF9pbmMxMDBrKS9maXJzdChlcHJlZF9pbmMxMDBrKSkgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBncm91cF9ieSh7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgIG1lYW5fcWkoYWNmX2luYzEwMGtfZGlmZiwgYWNmX2luYzEwMGtfcnIpICU+JQogICAgbXV0YXRlKGNoYW5nZSA9ICJQb3N0LUFDRiBjaGFuZ2UiKSAlPiUKICAgIHVuZ3JvdXAoKQogIAogICNjLiBjaGFuZ2UgaW4gc2xvcGUgcG9zdCB2cy4gcHJlLUFDRgogIHNsb3BlX2NoYW5nZSA8LSB7e21vZGVsX2RhdGF9fSAlPiUKICAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QsIHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgIGZpbHRlcih5ZWFyIT0xOTU3KSAlPiUKICAgIGFkZF9lcHJlZF9kcmF3cyh7e21vZGVsfX0pICU+JQogICAgbXV0YXRlKGluY18xMDBrID0gLmVwcmVkL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCkgJT4lCiAgICBncm91cF9ieSh5ZWFyLCB7e2dyb3VwaW5nX3Zhcn19LCBhY2ZfcGVyaW9kLCApICU+JQogICAgbWVhbl9xaShpbmNfMTAwaykgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBtdXRhdGUobl95ZWFycyA9IGxlbmd0aCh5ZWFyKSwgLmJ5PWMoYWNmX3BlcmlvZCwge3tncm91cGluZ192YXJ9fSkpICU+JQogICAgc3VtbWFyaXNlKHBjdF9jaGFuZ2VfZXByZWRfb3ZlcmFsbCA9ICgoKGxhc3QoaW5jXzEwMGspIC0gZmlyc3QoaW5jXzEwMGspKS9maXJzdChpbmNfMTAwaykpKSwKICAgICAgICAgICAgICBwY3RfY2hhbmdlX2xvd2VyX292ZXJhbGwgPSAoKChsYXN0KC5sb3dlcikgLSBmaXJzdCgubG93ZXIpKS9maXJzdCgubG93ZXIpKSksCiAgICAgICAgICAgICAgcGN0X2NoYW5nZV91cHBlcl9vdmVyYWxsID0gKCgobGFzdCgudXBwZXIpIC0gZmlyc3QoLnVwcGVyKSkvZmlyc3QoLnVwcGVyKSkpLAogICAgICAKICAgICAgICAgICAgICBwY3RfY2hhbmdlX2VwcmVkX2FubnVhbCA9ICgoKGxhc3QoaW5jXzEwMGspIC0gZmlyc3QoaW5jXzEwMGspKS9maXJzdChpbmNfMTAwaykpL25feWVhcnMpLAogICAgICAgICAgICAgIHBjdF9jaGFuZ2VfbG93ZXJfYW5udWFsID0gKCgobGFzdCgubG93ZXIpIC0gZmlyc3QoLmxvd2VyKSkvZmlyc3QoLmxvd2VyKSkvbl95ZWFycyksCiAgICAgICAgICAgICAgcGN0X2NoYW5nZV91cHBlcl9hbm51YWwgPSAoKChsYXN0KC51cHBlcikgLSBmaXJzdCgudXBwZXIpKS9maXJzdCgudXBwZXIpKS9uX3llYXJzKSwKICAgICAgICAgICAgICAuYnkgPSBjKGFjZl9wZXJpb2QsIHt7Z3JvdXBpbmdfdmFyfX0pKSAlPiUKICAgIGRpc3RpbmN0KCkgJT4lCiAgICBtdXRhdGUoY2hhbmdlID0gIlNsb3BlIGNoYW5nZSIpCgogIGxzdChpbW1lZGlhdGVfY2hhbmdlLCBwb3N0X2NoYW5nZSwgc2xvcGVfY2hhbmdlKQogICAgCn0KCmBgYAoKCkZ1bmN0aW9uIGZvciBjYWxjdWxhdGluZyBkaWZmZXJlbmNlIGZyb20gY291bnRlcmZhY3R1YWwKCmBgYHtyfQpjYWxjdWF0ZV9jb3VudGVyZmFjdHVhbCA8LSBmdW5jdGlvbihtb2RlbF9kYXRhLCBtb2RlbCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciwgZ3JvdXBpbmdfdmFyPU5VTEwpewogIAogICNlZmZlY3QgaW4gMTk1OCB2cy4gY291bnRlcmZhY3R1YWwKICBjb3VudGVyZmFjdCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0ge3ttb2RlbH19LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IHt7bW9kZWxfZGF0YX19ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gImEuIHByZS1hY2YiKSkgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCB5ZWFyLCB7e2dyb3VwaW5nX3Zhcn19LCBhY2ZfcGVyaW9kKSAlPiUKICAgICAgbXV0YXRlKC5lcHJlZF9pbmNfY291bnRlcmYgPSAuZXByZWQve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwLCAuZXByZWRfY291bnRlcmY9LmVwcmVkKSAgJT4lCiAgICAgIGZpbHRlcih5ZWFyPjE5NTcpICU+JQogICAgICB1bmdyb3VwKCkgJT4lCiAgICAgIHNlbGVjdCh5ZWFyLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwgLmRyYXcsIC5lcHJlZF9jb3VudGVyZiwgLmVwcmVkX2luY19jb3VudGVyZikKICAKICAjQ2FsY3VhdGUgaW5jaWRlbmNlIHBlciBkcmF3LCB0aGVuIHN1bW1hcmlzZS4KICBwb3N0X2NoYW5nZSA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0ge3ttb2RlbH19LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IHt7bW9kZWxfZGF0YX19ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSwgYWNmX3BlcmlvZCkpICU+JQogICAgICBncm91cF9ieSguZHJhdywgeWVhciwge3tncm91cGluZ192YXJ9fSwgYWNmX3BlcmlvZCkgJT4lCiAgICAgIG11dGF0ZSguZXByZWRfaW5jID0gLmVwcmVkL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCkgICU+JQogICAgICBmaWx0ZXIoeWVhcj4xOTU3KSAlPiUKICAgICAgdW5ncm91cCgpICU+JQogICAgICBzZWxlY3QoeWVhciwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0sIC5kcmF3LCAuZXByZWQsIC5lcHJlZF9pbmMpIAogIApjb3VudGVyX3Bvc3QgPC0KICBsZWZ0X2pvaW4oY291bnRlcmZhY3QsIHBvc3RfY2hhbmdlKSAlPiUKICAgIG11dGF0ZShjYXNlc19hdmVydGVkID0gLmVwcmVkX2NvdW50ZXJmLS5lcHJlZCwKICAgICAgICAgIGRpZmZfaW5jMTAwayA9IC5lcHJlZF9pbmMgLSAuZXByZWRfaW5jX2NvdW50ZXJmLAogICAgICAgICAgIHJyX2luYzEwMGsgPSAuZXByZWRfaW5jLy5lcHJlZF9pbmNfY291bnRlcmYsCiAgICAgICAgICAgcGN0X2luYzEwMGsgPSAoLmVwcmVkX2luYyAtIC5lcHJlZF9pbmNfY291bnRlcmYpLy5lcHJlZF9pbmMpICU+JQogICAgZ3JvdXBfYnkoeWVhciwge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICBtZWFuX3FpKGNhc2VzX2F2ZXJ0ZWQsIGRpZmZfaW5jMTAwaywgcnJfaW5jMTAwaywgcGN0X2luYzEwMGspICU+JQogICAgdW5ncm91cCgpCgpsc3QoY291bnRlcl9wb3N0KQoKfQoKCgpgYGAKCgoKCiMjIyAyLiBEYXRhCgpJbXBvcnQgZGF0YXNldHMgZm9yIGFuYWx5c2lzCgojIyMjIDIuMSBTaGFwZWZpbGVzCgoKCmBgYHtyfQoKZ2xhc2dvd193YXJkc18xOTUxIDwtIHN0X3JlYWQoImdsYXNnb3dfd2FyZHNfMTk1OS5nZW9qc29uIikKCmBgYAoKIyMjIDMuIERlbm9taW5hdG9ycwoKTG9hZCBpbiB0aGUgZGF0YXNldHMgZm9yIGRlbm9ub21pYXRvcnMsIGFuZCBjaGVjayBmb3IgY29uc2lzdGVuY3kuCgpgYGB7cn0KCm92ZXJhbGxfcG9wcyA8LSByZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLCBzaGVldCA9ICJvdmVyYWxsX3BvcHVsYXRpb24iKQoKb3ZlcmFsbF9wb3BzICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCiNzaGlmdCB5ZWFyIHRvIG1pZHBvaW50Cm92ZXJhbGxfcG9wcyA8LSBvdmVyYWxsX3BvcHMgJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpCgpgYGAKCk5vdGUsIHdlIGhhdmUgdGhyZWUgcG9wdWxhdGlvbiBlc3RpbWF0ZXM6CgoxLiBQb3B1bGF0aW9uIHdpdGhvdXQgaW5zdGl0dXRpb25hbGlzZWQgcGVvcGxlIG9yIHBlb3BsZSBpbiBzaGlwcGluZwoyLiBQb3B1bGF0aW9uIGluIGluc3RpdHV0aW9ucwozLiBQb3B1bGF0aW9uIGluIHNoaXBwaW5nCgooUG9wdWxhdGlvbiBpbiBzaGlwcGluZyBpcyBlc3RpbWF0ZWQgZnJvbSB0aGUgMTk1MSBjZW5zdXMsIHNvIGlzIHRoZSBzYW1lIGZvciBtb3N0IHllYXJzKQoKIyMjIyAzLjEgT3ZlcmFsbCBwb3B1bGF0aW9uCgpGaXJzdCwgcGxvdCB0aGUgdG90YWwgcG9wdWxhdGlvbgoKYGBge3J9CgpvdmVyYWxsX3BvcHMgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT10b3RhbF9wb3B1bGF0aW9uLCB4PXllYXIyKSwgYWxwaGE9MC41LCBjb2xvdXIgPSAibWVkaXVtc2VhZ3JlZW4iLCBmaWxsPSJtZWRpdW1zZWFncmVlbiIpICsKICBnZW9tX3BvaW50KGFlcyh5PXRvdGFsX3BvcHVsYXRpb24sIHg9eWVhcjIpLCBjb2xvdXIgPSAibWVkaXVtc2VhZ3JlZW4iKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IHRvdGFsIHBvcHVsYXRpb24iLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIlBvcHVsYXRpb24iLAogICAgY2FwdGlvbiA9ICJNaWQteWVhciBlc3RpbWF0ZXNcbk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICkgKwogIHRoZW1lX2dnZGlzdCgpCgoKYGBgCgpOb3cgdGhlIHBvcHVsYXRpb24gZXhjbHVkaW5nIGluc3RpdHV0aW9uYWxpc2VkIGFuZCBzaGlwcGluZyBwb3B1bGF0aW9uCgpgYGB7cn0KCm92ZXJhbGxfcG9wcyAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PXBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIHg9eWVhcjIpLCBhbHBoYT0wLjUsIGNvbG91ciA9ICJwdXJwbGUiLCBmaWxsPSJwdXJwbGUiKSArCiAgZ2VvbV9wb2ludChhZXMoeT1wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCB4PXllYXIyKSwgY29sb3VyID0gInB1cnBsZSIpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogcG9wdWxhdGlvbiBleGNsdWRpbmcgaW5zdGl0dXRpb25hbGlzZWQgYW5kIHNoaXBwaW5nIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MyIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJQb3B1bGF0aW9uIiwKICAgIGNhcHRpb24gPSAiTWlkLXllYXIgZXN0aW1hdGVzXG5NYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIKICApICsKICB0aGVtZV9nZ2Rpc3QoKQoKCmBgYAoKIyMjIyAzLjIgUG9wdWxhdGlvbiBieSBXYXJkCgpUaGVyZSBhcmUgNSBEaXZpc2lvbnMgY29udGFpbmluZyAzNyBXYXJkcyBpbiB0aGUgR2xhc2dvdyBDb3Jwb3JhdGlvbiwgd2l0aCBjb25zaXN0ZW50IGJvdW5kYXJpZXMgb3ZlciB0aW1lLgoKYGBge3J9CiNsb29rLXVwIHRhYmxlIGZvciBkaXZpc2lvbnMgYW5kIHdhcmRzCndhcmRfbG9va3VwIDwtIHJlYWRfeGxzeChwYXRoID0gIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsIHNoZWV0ID0gImRpdmlzaW9uc193YXJkcyIpCgoKd2FyZF9wb3BzIDwtIHJlYWRfeGxzeChwYXRoID0gIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsIHNoZWV0ID0gIndhcmRfcG9wdWxhdGlvbiIpCgp3YXJkX3BvcHMgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSAmICEoeWVhciksICB+Y29tbWEoLikpKSAlPiUKICBkYXRhdGFibGUoKQoKI3NoaWZ0IHllYXIgdG8gbWlkcG9pbnQKd2FyZF9wb3BzIDwtIHdhcmRfcG9wcyAlPiUKICBtdXRhdGUoeWVhcjIgPSB5ZWFyKzAuNSkKCiNHZXQgdGhlIERpdmlzaW9uIHBvcHVsYXRpb24KZGl2aXNpb25fcG9wcyA8LSB3YXJkX3BvcHMgJT4lCiAgZ3JvdXBfYnkoZGl2aXNpb24sIHllYXIpICU+JQogIHN1bW1hcmlzZShwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwID0gc3VtKHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIGluc3RpdHV0aW9ucyA9IHN1bShpbnN0aXR1dGlvbnMsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIHNoaXBwaW5nID0gc3VtKHNoaXBwaW5nLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICB0b3RhbF9wb3B1bGF0aW9uID0gc3VtKHRvdGFsX3BvcHVsYXRpb24sIG5hLnJtID0gVFJVRSkpCgpkaXZpc2lvbl9wb3BzICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCmBgYAoKUGxvdCB0aGUgb3ZlcmFsbCBwb3B1bGF0aW9uIGJ5IERpdmlzaW9uIGFuZCBXYXJkCgpgYGB7cn0KCmRpdmlzaW9uX3BvcHMgJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9dG90YWxfcG9wdWxhdGlvbiwgeD15ZWFyMiwgY29sb3VyPWRpdmlzaW9uLCBmaWxsPWRpdmlzaW9uKSwgYWxwaGE9MC41KSArCiAgZ2VvbV9wb2ludChhZXMoeT10b3RhbF9wb3B1bGF0aW9uLCB4PXllYXIyLCBjb2xvdXI9ZGl2aXNpb24pKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBmYWNldF93cmFwKGRpdmlzaW9ufi4pICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZChuYW1lID0gIiIpICsKICBzY2FsZV9jb2xvdXJfdmlyaWRpc19kKG5hbWUgPSAiIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiB0b3RhbCBwb3B1bGF0aW9uIGJ5IERpdmlzaW9uIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MyIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJQb3B1bGF0aW9uIiwKICAgIGNhcHRpb24gPSAiTWlkLXllYXIgZXN0aW1hdGVzXG5NYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIKICApICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgoKYGBgCgpgYGB7cn0KCndhcmRfcG9wcyAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PXRvdGFsX3BvcHVsYXRpb24sIHg9eWVhcjIsIGNvbG91cj1kaXZpc2lvbiwgZmlsbD1kaXZpc2lvbiksIGFscGhhPTAuNSkgKwogIGdlb21fcG9pbnQoYWVzKHk9dG90YWxfcG9wdWxhdGlvbiwgeD15ZWFyMiwgY29sb3VyPWRpdmlzaW9uKSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgZmFjZXRfd3JhcCh3YXJkfi4sIG5jb2w9NikgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKG5hbWUgPSAiRGl2aXNpb24iKSArCiAgc2NhbGVfY29sb3VyX3ZpcmlkaXNfZChuYW1lID0gIkRpdmlzaW9uIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENpdHk6IHRvdGFsIHBvcHVsYXRpb24gYnkgV2FyZCIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMiLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiUG9wdWxhdGlvbiIsCiAgICBjYXB0aW9uID0gIk1pZC15ZWFyIGVzdGltYXRlc1xuTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1NykiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczEucG5nIiksIGhlaWdodD0xMCwgd2lkdGg9MTIpCgpgYGAKCkFwcHJveGltYXRlbHksIGhvdyBtYW55IHBlcnNvbi15ZWFycyBvZiBmb2xsb3ctdXAgZG8gd2UgaGF2ZT8KCmBgYHtyfQoKb3ZlcmFsbF9wb3BzICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzdW1tYXJpc2UoYWNyb3NzKHllYXIsIGxlbmd0aCwgLm5hbWVzID0gInllYXJzIiksCiAgICAgICAgICAgIGFjcm9zcyhjKHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIHRvdGFsX3BvcHVsYXRpb24pLCBzdW0pKSAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLmRvdWJsZSksIGNvbW1hKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpgYGAKCkNoYW5nZSBpbiBwb3B1bGF0aW9uIGJ5IHdhcmQKCmBgYHtyfQoKd2FyZF9wb3BzICU+JQogIGdyb3VwX2J5KHdhcmQpICU+JQogIHN1bW1hcmlzZShwY3RfY2hhbmdlX3BvcCA9IChsYXN0KHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXApIC0gZmlyc3QocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCkpL2ZpcnN0KHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXApKSAlPiUKICBtdXRhdGUocGN0X2NoYW5nZV9wb3AgPSBwZXJjZW50KHBjdF9jaGFuZ2VfcG9wKSkgJT4lCiAgYXJyYW5nZShwY3RfY2hhbmdlX3BvcCkgJT4lCiAgZGF0YXRhYmxlKCkKICAKCgpgYGAKCgojIyMjIDMuMyBQb3B1bGF0aW9uIGJ5IGFnZSBhbmQgc2V4CgpgYGB7cn0KCmFnZV9zZXggPC0gcmVhZF94bHN4KHBhdGggPSAiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4Iiwgc2hlZXQgPSAiYWdlX3NleF9wb3B1bGF0aW9uIikgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKG1hbGUsIGZlbWFsZSksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInNleCIpCgojY29sbGFwc2UgZG93biB0byBzbWFsbGVyIGFnZSBncm91cHMgdG8gYmUgbWFuYWdlYWJsZQphZ2Vfc2V4IDwtIGFnZV9zZXggJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShhZ2UgPSBjYXNlX3doZW4oYWdlID09ICIwIHRvIDQiIH4gIjAwIHRvIDA0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiNSB0byA5IiB+ICIwNSB0byAxNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2UgPT0gIjEwIHRvIDE0IiB+ICIwNSB0byAxNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2UgPT0gIjE1IHRvIDE5IiB+ICIxNSB0byAyNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2UgPT0gIjIwIHRvIDI0IiB+ICIxNSB0byAyNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2UgPT0gIjI1IHRvIDI5IiB+ICIyNSB0byAzNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2UgPT0gIjMwIHRvIDM0IiB+ICIyNSB0byAzNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2UgPT0gIjM1IHRvIDM5IiB+ICIzNSB0byA0NCIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2UgPT0gIjQwIHRvIDQ0IiB+ICIzNSB0byA0NCIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2UgPT0gIjQ1IHRvIDQ5IiB+ICI0NSB0byA1OSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2UgPT0gIjUwIHRvIDU0IiB+ICI0NSB0byA1OSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2UgPT0gIjU1IHRvIDU5IiB+ICI0NSB0byA1OSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIjYwICYgdXAiKSkgJT4lCiAgZ3JvdXBfYnkoeWVhciwgYWdlLCBzZXgpICU+JQogIG11dGF0ZSh2YWx1ZSA9IHN1bSh2YWx1ZSkpICU+JQogIHVuZ3JvdXAoKQoKCgptX2FnZV9zZXggPC0gbG0odmFsdWUgfiBzcGxpbmVzOjpucyh5ZWFyLCBrbm90cyA9IDMpKmFnZSpzZXgsIGRhdGEgPSBhZ2Vfc2V4KQoKc3VtbWFyeShtX2FnZV9zZXgpCgphZ2VfbGV2ZWxzIDwtIGFnZV9zZXggJT4lIHNlbGVjdChhZ2UpICU+JSBkaXN0aW5jdCgpICU+JSBwdWxsKCkgCgphZ2Vfc2V4X25kIDwtIAogIGNyb3NzaW5nKAogICAgYWdlPWFnZV9sZXZlbHMsCiAgICBzZXg9YygibWFsZSIsICJmZW1hbGUiKSwKICAgIHllYXIgPSAxOTUwOjE5NjMKICApCgpwcmVkX3BvcHMgPC0gYWdlX3NleF9uZCAlPiUgbW9kZWxyOjphZGRfcHJlZGljdGlvbnMobV9hZ2Vfc2V4KQoKcHJlZF9wb3BzICU+JQogIGdncGxvdChhZXMoeD15ZWFyLCB5PXByZWQsIGNvbG91cj1hZ2UpKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoKSArCiAgZmFjZXRfZ3JpZChzZXh+LikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSwgbGltaXRzID0gYygwLCAxMjUwMDApKQoKI0hvdyB3ZWxsIGRvIHRoZXkgbWF0Y2ggdXAgd2l0aCBvdXIgb3ZlcmFsbCBwb3B1bGF0aW9ucz8KcHJlZF9wb3BzICU+JQogIGdyb3VwX2J5KHllYXIpICU+JQogIHN1bW1hcmlzZShzdW1fcHJlZF9wb3AgPSBzdW0ocHJlZCkpICU+JQogIHJpZ2h0X2pvaW4ob3ZlcmFsbF9wb3BzKSAlPiUKICBzZWxlY3QoeWVhciwgc3VtX3ByZWRfcG9wLCBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCB0b3RhbF9wb3B1bGF0aW9uKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMoc3VtX3ByZWRfcG9wLCBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCB0b3RhbF9wb3B1bGF0aW9uKSkgJT4lCiAgZ2dwbG90KGFlcyh4PXllYXIsIHk9dmFsdWUsIGNvbG91cj1uYW1lKSkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hLCBsaW1pdHMgPSBjKDgwMDAwMCwgMTI1MDAwMCkpCgpwcmVkX3BvcHMgJT4lCiAgZ3JvdXBfYnkoeWVhciwgc2V4KSAlPiUKICBzdW1tYXJpc2Uoc3VtID0gc3VtKHByZWQpKSAlPiUKICBncm91cF9ieSh5ZWFyKSAlPiUKICBtdXRhdGUoc2V4X3JhdGlvID0gZmlyc3Qoc3VtKS9sYXN0KHN1bSkpCmBgYAoKUG9wdWxhdGlvbiBweXJhbWlkcwoKYGBge3J9CgpsYWJlbF9hYnMgPC0gZnVuY3Rpb24oeCkgewogIGNvbW1hKGFicyh4KSkKfQoKCnByZWRfcG9wcyAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgbXV0YXRlKHllYXJfcG9wID0gc3VtKHByZWQpLAogICAgICAgICBhZ2Vfc2V4X3BjdCA9IHBlcmNlbnQocHJlZC95ZWFyX3BvcCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXg9PSJtYWxlIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09ImZlbWFsZSIgfiAiRmVtYWxlIikpICU+JQogIGdncGxvdCgKICAgIGFlcyh4ID0gYWdlLCBmaWxsID0gc2V4LCAKICAgICAgICB5ID0gaWZlbHNlKHRlc3QgPSBzZXggPT0gIkZlbWFsZSIseWVzID0gLXByZWQsIG5vID0gcHJlZCkpKSArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGFnZV9zZXhfcGN0KSwKICAgICAgICAgICAgcG9zaXRpb249IHBvc2l0aW9uX3N0YWNrKHZqdXN0PTAuNSksIGNvbG91cj0id2hpdGUiLCBzaXplPTIuNSkgKwogIGZhY2V0X3dyYXAoeWVhcn4uLCBuY29sPTcpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9hYnMpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJtZWRpdW1zZWFncmVlbiIsICJwdXJwbGUiKSwgbmFtZT0iIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT05MCwgaGp1c3QgPSAxLCB2anVzdD0wLjUpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKICBsYWJzKHg9IiIsIHk9IiIpIAoKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3MyLnBuZyIpLCB3aWR0aD0xMCkKCgpgYGAKCk5vdCBwZXJmZWN0LCBidXQgcmVzb25hYmx5IGdvb2QuIEJ1dCBhaGhoaGguLi4gdGhlIGFnZSBncm91cHMgZG9uJ3QgYWxpZ24gd2l0aCB0aGUgY2FzZSBub3RpZmljYXRpb24gYWdlIGdyb3VwcyEgQ29tZSBiYWNrIHRvIHRoaW5rIGFib3V0IHRoaXMgbGF0ZXIuCgoKIyMjIDQuIFR1YmVyY3Vsb3NpcyBjYXNlcwoKSW1wb3J0IHRoZSB0dWJlcmN1bG9zaXMgY2FzZXMgZGF0YXNldAoKCiMjIyMgNC4xIE92ZXJhbGwgbm90aWZpY2F0aW9ucwoKT3ZlcmFsbCwgYnkgeWVhci4KCmBgYHtyfQoKY2FzZXNfYnlfeWVhciA8LSByZWFkX3hsc3goIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsIHNoZWV0ID0gImJ5X3llYXIiKQoKY2FzZXNfYnlfeWVhciU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgojc2hpZnQgeWVhciB0byBtaWRwb2ludApjYXNlc19ieV95ZWFyIDwtIGNhc2VzX2J5X3llYXIgJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpCgpgYGAKClBsb3QgdGhlIG92ZXJhbGwgbnVtYmVyIG9mIGNhc2Ugbm90aWZpZWQgcGVyIHllYXIsIGJ5IHB1bG1vbmFyeSBhbmQgZXh0cmEgcHVsbW9uYXJ5IGNsYXNzaWZpY2F0aW9uLgoKYGBge3J9CgpjYXNlc19ieV95ZWFyICU+JQogIHNlbGVjdCgtdG90YWxfbm90aWZpY2F0aW9ucywgLXllYXIpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhwdWxtb25hcnlfbm90aWZpY2F0aW9ucywgYG5vbi1wdWxtb25hcnlfbm90aWZpY2F0aW9uc2ApKSAlPiUKICBtdXRhdGUobmFtZSA9IGNhc2Vfd2hlbihuYW1lID09ICJwdWxtb25hcnlfbm90aWZpY2F0aW9ucyIgfiAiUHVsbW9uYXJ5IFRCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJub24tcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMiIH4gIkV4dHJhLXB1bG1vbmFyeSBUQiIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PXZhbHVlLCB4PXllYXIyLCBncm91cCA9IG5hbWUsIGZpbGw9bmFtZSksIGFscGhhPTAuNSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscykgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsIG5hbWU9IiIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogVHViZXJjdWxvc2lzIG5vdGlmaWNhdGlvbnMiLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzLCBieSBUQiBkaXNlYXNlIGNsYXNzaWZpY2F0aW9uIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIk51bWJlciBvZiBjYXNlcyIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKICAKCmBgYAoKIyMjIyA0LjIgTm90aWZpY2F0aW9ucyBieSBEaXZpc2lvbgoKUmVhZCBpbiB0aGUgZGF0YXNldHMgYW5kIG1lcmdlIHRvZ2V0aGVyLgoKYGBge3J9CgojbGlzdCBhbGwgdGhlIHNoZWV0cwphbGxfc2hlZXRzIDwtIGV4Y2VsX3NoZWV0cygiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4IikKCiNnZXQgdGhlIHdhcmQgc2hlZXRzCndhcmRfc2hlZXRzIDwtIGVuZnJhbWUoYWxsX3NoZWV0cykgJT4lCiAgZmlsdGVyKGdyZXBsKCJieV93YXJkIiwgdmFsdWUpKSAlPiUKICBwdWxsKHZhbHVlKQoKCmNhc2VzX2J5X3dhcmRfc2V4X3llYXIgPC0gbWFwX2RmKHdhcmRfc2hlZXRzLCB+cmVhZF94bHN4KHBhdGggPSAiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGVldCA9IC4pKQoKY2FzZXNfYnlfd2FyZF9zZXhfeWVhciAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgpgYGAKCkFnZ3JlZ2F0ZSB0b2dldGhlciB0byBjYXNlIGNhc2VzIGJ5IGRpdmlzaW9uCgpgYGB7cn0KCmNhc2VzX2J5X2RpdmlzaW9uIDwtIGNhc2VzX2J5X3dhcmRfc2V4X3llYXIgJT4lCiAgbGVmdF9qb2luKHdhcmRfbG9va3VwKSAlPiUKICBncm91cF9ieShkaXZpc2lvbiwgeWVhciwgdGJfdHlwZSkgJT4lCiAgc3VtbWFyaXNlKGNhc2VzID0gc3VtKGNhc2VzLCBuYS5ybSA9IFRSVUUpKQoKI3NoaWZ0IHllYXIgdG8gbWlkcG9pbnQKY2FzZXNfYnlfZGl2aXNpb24gPC0gY2FzZXNfYnlfZGl2aXNpb24gJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpICU+JQogIHVuZ3JvdXAoKQoKY2FzZXNfYnlfZGl2aXNpb24gICU+JQogIHNlbGVjdCgteWVhcjIpICU+JQogIHNlbGVjdCh5ZWFyLCBldmVyeXRoaW5nKCkpICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpjYXNlc19ieV9kaXZpc2lvbiAlPiUKICBtdXRhdGUodGJfdHlwZSA9IGNhc2Vfd2hlbih0Yl90eXBlID09ICJQdWxtb25hcnkiIH4gIlB1bG1vbmFyeSBUQiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGJfdHlwZSA9PSAiTm9uLVB1bG1vbmFyeSIgfiAiRXh0cmEtcHVsbW9uYXJ5IFRCIikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9Y2FzZXMsIHg9eWVhcjIsIGdyb3VwID0gdGJfdHlwZSwgZmlsbD10Yl90eXBlKSwgYWxwaGE9MC41KSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBmYWNldF93cmFwKGRpdmlzaW9ufi4sIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBUdWJlcmN1bG9zaXMgbm90aWZpY2F0aW9ucyBieSBEaXZpc2lvbiIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMsIGJ5IFRCIGRpc2Vhc2UgY2xhc3NpZmljYXRpb24iLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiTnVtYmVyIG9mIGNhc2VzIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1Nylcbk5vdGU6IGV4dHJhLXB1bG1vbmFyeSBUQiBjYXNlcyBieSBEaXZpc2lvbi9XYXJkIG5vdCByZXBvcnRlZCBpbiAxOTYyLTE5NjMiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKYGBgCgojIyMjIDQuMyBOb3RpZmljYXRpb25zIGJ5IHdhcmQKCmBgYHtyfQoKCmNhc2VzX2J5X3dhcmQgPC0gY2FzZXNfYnlfd2FyZF9zZXhfeWVhciAlPiUKICBncm91cF9ieSh3YXJkLCB5ZWFyLCB0Yl90eXBlKSAlPiUKICBzdW1tYXJpc2UoY2FzZXMgPSBzdW0oY2FzZXMsIG5hLnJtID0gVFJVRSkpICU+JQogIHVuZ3JvdXAoKQoKY2FzZXNfYnlfd2FyZCAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIHNlbGVjdCh5ZWFyLCBldmVyeXRoaW5nKCkpICU+JQogIGRhdGF0YWJsZSgpCgojc2hpZnQgeWVhciB0byBtaWRwb2ludApjYXNlc19ieV93YXJkIDwtIGNhc2VzX2J5X3dhcmQgJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpCgpjYXNlc19ieV93YXJkICU+JQogIG11dGF0ZSh0Yl90eXBlID0gY2FzZV93aGVuKHRiX3R5cGUgPT0gIlB1bG1vbmFyeSIgfiAiUHVsbW9uYXJ5IFRCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB0Yl90eXBlID09ICJOb24tUHVsbW9uYXJ5IiB+ICJFeHRyYS1wdWxtb25hcnkgVEIiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT1jYXNlcywgeD15ZWFyMiwgZ3JvdXAgPSB0Yl90eXBlLCBmaWxsPXRiX3R5cGUpLCBhbHBoYT0wLjgpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkgKwogIGZhY2V0X3dyYXAod2FyZH4uLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsIG5hbWU9IiIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogVHViZXJjdWxvc2lzIG5vdGlmaWNhdGlvbnMgYnkgV2FyZCIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMsIGJ5IFRCIGRpc2Vhc2UgY2xhc3NpZmljYXRpb24iLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiTnVtYmVyIG9mIGNhc2VzIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1Nylcbk5vdGU6IGV4dHJhLXB1bG1vbmFyeSBUQiBjYXNlcyBieSBEaXZpc2lvbi9XYXJkIG5vdCByZXBvcnRlZCBpbiAxOTYyLTE5NjMiCiAgKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgoKYGBgCgojIyMjIDQuNCBOb3RpZmljYXRpb25zIGJ5IGFnZSBhbmQgc2V4CgpBcyB3ZSBkb24ndCBoYXZlIGRlbm9taW5hdG9ycywgd2Ugd2lsbCBqdXN0IG1vZGVsIHRoZSBjaGFuZ2UgaW4gY291bnRzLgoKYGBge3J9CgojbGlzdCBhbGwgdGhlIHNoZWV0cwphbGxfc2hlZXRzIDwtIGV4Y2VsX3NoZWV0cygiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4IikKCiNnZXQgdGhlIHdhcmQgc2hlZXRzCmFnZV9zZXhfc2hlZXRzIDwtIGVuZnJhbWUoYWxsX3NoZWV0cykgJT4lCiAgZmlsdGVyKGdyZXBsKCJieV9hZ2Vfc2V4IiwgdmFsdWUpKSAlPiUKICBwdWxsKHZhbHVlKQoKCmNhc2VzX2J5X2FnZV9zZXggPC0gbWFwX2RmKGFnZV9zZXhfc2hlZXRzLCB+cmVhZF94bHN4KHBhdGggPSAiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGVldCA9IC4pKQoKY2FzZXNfYnlfYWdlX3NleCAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgoKYGBgCgoKCgojIyMgNSBUQiBpbmNpZGVuY2UKCiMjIyMgNS4xIE92ZXJhbGwgVEIgaW5jaWRlbmNlCgpOb3cgY2FsY3VsYXRlIGluY2lkZW5jZSBwZXIgMTAwLDAwMCBwb3B1bGF0aW9uCgpNZXJnZSB0aGUgbm90aWZpY2F0aW9uIGFuZCBwb3B1bGF0aW9uIGRlbm9taW5hdG9yIGRhdGFzZXRzIHRvZ2V0aGVyLgoKSGVyZSB3ZSBuZWVkIHRvIGluY2x1ZGUgdGhlIHdob2xlIHBvcHVsYXRpb24gKHdpdGggc2hpcHBpbmcgYW5kIGluc3RpdHV0aW9ucykgYXMgdGhleSBhcmUgaW5jbHVkZWQgaW4gdGhlIG5vdGlmaWNhdGlvbnMuCgpgYGB7cn0KCm92ZXJhbGxfaW5jIDwtIG92ZXJhbGxfcG9wcyAlPiUKICBsZWZ0X2pvaW4oY2FzZXNfYnlfeWVhcikKCm92ZXJhbGxfaW5jIDwtIG92ZXJhbGxfaW5jICU+JQogIG11dGF0ZShpbmNfcHVsbV8xMDBrID0gcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMvdG90YWxfcG9wdWxhdGlvbioxMDAwMDAsCiAgICAgICAgIGluY19lcF8xMDBrID0gYG5vbi1wdWxtb25hcnlfbm90aWZpY2F0aW9uc2AvdG90YWxfcG9wdWxhdGlvbioxMDAwMDAsCiAgICAgICAgIGluY18xMDBrID0gdG90YWxfbm90aWZpY2F0aW9ucy90b3RhbF9wb3B1bGF0aW9uKjEwMDAwMCkKCm92ZXJhbGxfaW5jICU+JQogIHNlbGVjdCh5ZWFyLCBpbmNfMTAwaywgaW5jX3B1bG1fMTAwaywgaW5jX2VwXzEwMGspICU+JQogIG11dGF0ZV9hdCgudmFycyA9IHZhcnMoaW5jXzEwMGssIGluY19wdWxtXzEwMGssIGluY19lcF8xMDBrKSwKICAgICAgICAgICAgLmZ1bnMgPSBmdW5zKHJvdW5kKSkgJT4lCiAgZGF0YXRhYmxlKCkKCmBgYAoKYGBge3J9CgpvdmVyYWxsX2luYyAlPiUKICBzZWxlY3QoeWVhcjIsIGluY19wdWxtXzEwMGssIGluY19lcF8xMDBrKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMoaW5jX3B1bG1fMTAwaywgYGluY19lcF8xMDBrYCkpICU+JQogIG11dGF0ZShuYW1lID0gY2FzZV93aGVuKG5hbWUgPT0gImluY19wdWxtXzEwMGsiIH4gIlB1bG1vbmFyeSBUQiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9PSAiaW5jX2VwXzEwMGsiIH4gIkV4dHJhLXB1bG1vbmFyeSBUQiIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PXZhbHVlLCB4PXllYXIyLCBncm91cCA9IG5hbWUsIGZpbGw9bmFtZSksIGFscGhhPTAuNSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscykgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsIG5hbWU9IiIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogVHViZXJjdWxvc2lzIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUiLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzLCBieSBUQiBkaXNlYXNlIGNsYXNzaWZpY2F0aW9uIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIkNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKHBlciAxMDAsMDAwKSIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCgoKYGBgCgojIyMjIDUuMiBUQiBpbmNpZGVuY2UgYnkgRGl2aXNpb24KCmBgYHtyfQoKZGl2aXNpb25faW5jIDwtIGRpdmlzaW9uX3BvcHMgJT4lCiAgbGVmdF9qb2luKGNhc2VzX2J5X2RpdmlzaW9uKQoKCmRpdmlzaW9uX2luYyA8LSBkaXZpc2lvbl9pbmMgJT4lCiAgbXV0YXRlKGluY18xMDBrID0gY2FzZXMvdG90YWxfcG9wdWxhdGlvbioxMDAwMDApCgpkaXZpc2lvbl9pbmMgJT4lCiAgc2VsZWN0KHllYXIsIGRpdmlzaW9uLCB0Yl90eXBlLCBpbmNfMTAwaykgJT4lCiAgbXV0YXRlX2F0KC52YXJzID0gdmFycyhpbmNfMTAwayksCiAgICAgICAgICAgIC5mdW5zID0gZnVucyhyb3VuZCkpICU+JQogIGRhdGF0YWJsZSgpCgoKYGBgCgpgYGB7cn0KCmRpdmlzaW9uX2luYyAlPiUKICBtdXRhdGUodGJfdHlwZSA9IGNhc2Vfd2hlbih0Yl90eXBlID09ICJQdWxtb25hcnkiIH4gIlB1bG1vbmFyeSBUQiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGJfdHlwZSA9PSAiTm9uLVB1bG1vbmFyeSIgfiAiRXh0cmEtcHVsbW9uYXJ5IFRCIikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9aW5jXzEwMGssIHg9eWVhcjIsIGdyb3VwID0gdGJfdHlwZSwgZmlsbD10Yl90eXBlKSwgYWxwaGE9MC41KSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBmYWNldF93cmFwKGRpdmlzaW9ufi4pICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCBuYW1lPSIiKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IFR1YmVyY3Vsb3NpcyBjYXNlIG5vdGlmaWNhdGlvbiByYXRlLCBieSBEaXZpc2lvbiIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMsIGJ5IFRCIGRpc2Vhc2UgY2xhc3NpZmljYXRpb24iLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiQ2FzZSBub3RpZmljYXRpb24gcmF0ZSAocGVyIDEwMCwwMDApIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1Nylcbk5vdGU6IGV4dHJhLXB1bG1vbmFyeSBUQiBjYXNlcyBieSBEaXZpc2lvbi9XYXJkIG5vdCByZXBvcnRlZCBpbiAxOTYyLTE5NjMiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKCgpgYGAKCiMjIyMgNS4yIFRCIGluY2lkZW5jZSBieSBXYXJkCgpIZXJlIHdlIHdpbGwgZmlsdGVyIG91dCB0aGUgaW5zdGl0dXRpb25zIGFuZCBoYXJib3VyIGZyb20gdGhlIGRlbm9taW5hdG9ycywgYXMgd2UgZG9uJ3QgaGF2ZSByZWxpYWJsZSBwb3B1bGF0aW9uIGRlbm9taW5hdG9ycyBmb3IgdGhlbS4KCmBgYHtyfQoKd2FyZF9pbmMgPC0gd2FyZF9wb3BzICU+JQogIGxlZnRfam9pbihjYXNlc19ieV93YXJkKQoKCndhcmRfaW5jIDwtIHdhcmRfaW5jICU+JQogIG11dGF0ZShpbmNfMTAwayA9IGNhc2VzL3BvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAqMTAwMDAwKQoKd2FyZF9pbmMgJT4lCiAgc2VsZWN0KHllYXIsIHdhcmQsIHRiX3R5cGUsIGluY18xMDBrKSAlPiUKICBtdXRhdGVfYXQoLnZhcnMgPSB2YXJzKGluY18xMDBrKSwKICAgICAgICAgICAgLmZ1bnMgPSBmdW5zKHJvdW5kKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpgYGAKCgpgYGB7cn0KCndhcmRfaW5jICU+JQogIG11dGF0ZSh0Yl90eXBlID0gY2FzZV93aGVuKHRiX3R5cGUgPT0gIlB1bG1vbmFyeSIgfiAiUHVsbW9uYXJ5IFRCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB0Yl90eXBlID09ICJOb24tUHVsbW9uYXJ5IiB+ICJFeHRyYS1wdWxtb25hcnkgVEIiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT1pbmNfMTAwaywgeD15ZWFyMiwgZ3JvdXAgPSB0Yl90eXBlLCBmaWxsPXRiX3R5cGUpLCBhbHBoYT0wLjUpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkgKwogIGZhY2V0X3dyYXAod2FyZH4uKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBUdWJlcmN1bG9zaXMgY2FzZSBub3RpZmljYXRpb24gcmF0ZSwgYnkgV2FyZCIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMsIGJ5IFRCIGRpc2Vhc2UgY2xhc3NpZmljYXRpb24iLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiSW5jaWRlbmNlIChwZXIgMTAwLDAwMCkiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KVxuTm90ZTogZXh0cmEtcHVsbW9uYXJ5IFRCIGNhc2VzIGJ5IERpdmlzaW9uL1dhcmQgbm90IHJlcG9ydGVkIGluIDE5NjItMTk2MyIKICApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCgoKCmBgYAoKT24gYSBtYXAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQoKc3RfYXNfc2YobGVmdF9qb2luKHdhcmRfaW5jLCBnbGFzZ293X3dhcmRzXzE5NTEpKSAlPiUKICBmaWx0ZXIodGJfdHlwZT09IlB1bG1vbmFyeSIpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NmKGFlcyhmaWxsPWluY18xMDBrKSkgKwogIGZhY2V0X3dyYXAoeWVhcn4uLCBuY29sID0gNykgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG5hbWU9IkNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKHBlciAxMDAsMDAwKSIsCiAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9uID0gIkEiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDIsICJjbSIpLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKICBndWlkZXMoZmlsbD1ndWlkZV9jb2xvcmJhcih0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiKSkKCgoKYGBgCgoKIyMjIDYuIFRCIE1vcnRhbGl0eQoKIyMjIyA2LjEgT3ZlcmFsbCBNb3J0YWxpdHkKCkltcG9ydCB0aGUgVEIgbW9ydGFsaXR5IGRhdGEuCgpGaXJzdCwgb3ZlcmFsbCBkZWF0aHMuIE5vdGUgdGhhdCBpbiB0aGUgb3JpZ2luYWwgcmVwb3J0cywgd2UgaGF2ZSBhIHB1bG1vbmFyeSBUQiBkZWF0aCByYXRlIHBlciBtaWxsaW9uIGZvciBhbGwgeWVhcnMsIGFuZCBudW1iZXJzIG9mIHB1bG1vbmFyeSBUQiBkZWF0aHMgZm9yIGVhY2ggeWVhciBhcGFydCBmcm9tIDE5NTAuCgpgYGB7cn0KCiNnZXQgdGhlIG92ZXJhbGwgbW9ydGFsaXR5IHNoZWV0cwpkZWF0aHNfc2hlZXRzIDwtIGVuZnJhbWUoYWxsX3NoZWV0cykgJT4lCiAgZmlsdGVyKGdyZXBsKCJkZWF0aHMiLCB2YWx1ZSkpICU+JQogIHB1bGwodmFsdWUpCgoKb3ZlcmFsbF9kZWF0aHMgPC0gbWFwX2RmKGRlYXRoc19zaGVldHMsIH5yZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoZWV0ID0gLikpCgpvdmVyYWxsX2RlYXRocyAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgoKCmBgYAoKUGxvdCB0aGUgcmF3IG51bWJlcnMgb2YgcHVsbW9uYXJ5IGRlYXRocwoKYGBge3J9CgpvdmVyYWxsX2RlYXRocyAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT1wdWxtb25hcnlfZGVhdGhzKSkgKwogIGdlb21fbGluZShjb2xvdXIgPSAiI0RFMEQ5MiIpICsKICBnZW9tX3BvaW50KGNvbG91ciA9ICIjREUwRDkyIikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBsYWJzKHk9IlB1bG1vbmFyeSBUQiBkZWF0aHMgcGVyIHllYXIiLAogICAgICAgeCA9ICJZZWFyIiwKICAgICAgIHRpdGxlID0gIk51bWJlcnMgb2YgcHVsbW9uYXJ5IFRCIGRlYXRocyIsCiAgICAgICBzdWJ0aXRsZSA9ICJHbGFzZ293LCAxOTUwLTE5NjMiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KVxuTm90ZTogbm8gZGF0YSBmb3IgMTk1MCIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCgpgYGAKCk5vdyB0aGUgaW5jaWRlbmNlIG9mIHB1bG1vbmFyeSBUQiBkZWF0aAoKYGBge3J9Cm92ZXJhbGxfZGVhdGhzICU+JQogIGdncGxvdChhZXMoeD15ZWFyLCB5PXB1bG1vbmFyeV9kZWF0aF9yYXRlX3Blcl8xMDBrKSkgKwogIGdlb21fbGluZShjb2xvdXIgPSAiIzRENkNGQSIpICsKICBnZW9tX3BvaW50KGNvbG91ciA9ICIjNEQ2Q0ZBIikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscykgKwogIGxhYnMoeT0iQW5udWFsIGluY2lkZW5jZSBvZiBkZWF0aCAocGVyIDEwMCwwMDApIiwKICAgICAgIHggPSAiWWVhciIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczcucG5nIiksIHdpZHRoPTEwKQoKYGBgCgoKIyMjIDYuIFRhYmxlIDEKCk1ha2UgVGFibGUgMSBoZXJlLCBhbmQgc2F2ZSBmb3IgcHVibGljYXRpb24uCgpgYGB7cn0KCm92ZXJhbGxfcG9wcyAlPiUgCiAgc2VsZWN0KHllYXIsIHRvdGFsX3BvcHVsYXRpb24pICU+JQogIGxlZnRfam9pbihvdmVyYWxsX2luYyAlPiUKICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgCiAgICAgICAgICAgICAgICAgICAgIHB1bG1vbmFyeV9ub3RpZmljYXRpb25zLCBpbmNfcHVsbV8xMDBrLAogICAgICAgICAgICAgICAgICAgICBgbm9uLXB1bG1vbmFyeV9ub3RpZmljYXRpb25zYCwgaW5jX2VwXzEwMGssCiAgICAgICAgICAgICAgICAgICAgIHRvdGFsX25vdGlmaWNhdGlvbnMsIGluY18xMDBrKSkgJT4lCiAgbGVmdF9qb2luKG92ZXJhbGxfZGVhdGhzICU+JQogICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLAogICAgICAgICAgICAgICAgICAgICBwdWxtb25hcnlfZGVhdGhzLCBwdWxtb25hcnlfZGVhdGhfcmF0ZV9wZXJfMTAwaykpICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfnJvdW5kKC4sIGRpZ2l0cz0xKSkpICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgCgpgYGAKCgoKCiMjIyA3LiBPdmVyYWxsIHB1bG1vbmFyeSBUQiBtb2RlbAoKCiMjIyMgNy4xIEZJdCB0aGUgbW9kZWwgYW5kIHByaW9ycwoKRmlyc3QgbW9kZWwgd2lsbCBpbnZlc3RpZ2F0ZSB0aGUgaW1wYWN0IG9mIG1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIG9uIHB1bG1vbmFyeSBUQiBjYXNlIG5vdGlmaWNhdGlvbiByYXRlIHVzaW5nIGFuIGludGVycnVwdGVkIHRpbWUgc2VyaWVzIGFuYWx5c2lzLgoKU2V0IHVwIHRoZSBkYXRhCgpgYGB7cn0KCm1kYXRhMSA8LSBvdmVyYWxsX2luYyAlPiUKICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbih5ZWFyICVpbiUgYygxOTUwOjE5NTYpIH4gImEuIHByZS1hY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTcpIH4gImIuIGFjZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciAlaW4lIGMoMTk1ODoxOTYzKSB+ICJjLiBwb3N0LWFjZiIpKSAlPiUKICBtdXRhdGUoeV9udW0gPSAxOm5yb3coLikpICU+JQogIHJlbmFtZShleHRyYXB1bG1vbmFyeV9ub3RpZmljYXRpb25zID0gYG5vbi1wdWxtb25hcnlfbm90aWZpY2F0aW9uc2ApCgpgYGAKCgpXb3JrIG9uIHRoZSBwcmlvcnMgYSBiaXQKCkJhc2ljIHByaW9yCgpgYGB7cn0KCmJhc2ljX3ByaW9yIDwtIGMocHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9IEludGVyY2VwdCksCiAgICAgICAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDAuMjUpLCBjbGFzcyA9IGIpKQpgYGAKCkxvb2sgYXQgdGhlIG1lYW4gYW5kIHZhcmlhbmNlIG9mIGNvdW50cyAoY291bnRzIG9mIHB1bG1vbmFyeSBub3RpZmljYXRpb25zIGFyZSB3aGF0IHdlIGFyZSBwcmVkaWN0aW5nKQoKYGBge3J9CgojTWVhbiBvZiBjb3VudHMgcGVyIHllYXIKbWVhbihtZGF0YTEkcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMpCiN2YXJpYW5jZSBvZiBjb3VudHMgcGVyIHllYXIKdmFyKG1kYXRhMSRwdWxtb25hcnlfbm90aWZpY2F0aW9ucykKCmBgYAoKClF1aXRlIGEgYml0IG9mIG92ZXItZGlzcGVyc2lvbiBoZXJlLCBzbyBuZWdhdGl2ZSBiaW5vbWlhbCBkaXN0cmlidXRpb24gbWlnaHQgYmUgYSBiZXR0ZXIgY2hvaWNlIG9mIGRpc3RyaWJ1dGlvbmFsIGZhbWlseSB0aGFuIFBvaXNzb24uCgpTbGlnaHRseSBtb3JlIGluZm9ybWF0aXZlIHByaW9yICgid2Vha2x5IGluZm9ybWF0aXZlIiByZWFsbHkpCgpgYGB7cn0KCmdncGxvdChkYXRhID0gdGliYmxlKHggPSBzZXEoZnJvbSA9IDUwMCwgdG8gPSA1MDAwLCBieSA9IDEwKSksCiAgICAgICBhZXMoeCA9IHgsIHkgPSBkZ2FtbWEoeCwgc2hhcGUgPSAwLjEsIHJhdGUgPSAwLjAwMDAxKSkpICsKICBnZW9tX2FyZWEoY29sb3IgPSAidHJhbnNwYXJlbnQiLCAKICAgICAgICAgICAgZmlsbCA9ICIjREUwRDkyIikgKwogIHNjYWxlX3hfY29udGludW91cyhOVUxMKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDUwMCwgNTAwMCkpICsKICBnZ3RpdGxlKGV4cHJlc3Npb24oYnJtc35+Z2FtbWEoMC4xKiIsICIqMC4wMDAwMSl+c2hhcGV+cHJpb3IpKQoKCmBgYAoKRml0IGEgbW9kZWwgd2l0aCBvbmx5IHByaW9ycwoKYGBge3J9Cgp3aW5mb3JtX3ByaW9yIDwtIGMocHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9IEludGVyY2VwdCksCiAgICAgICAgICAgICAgICAgIHByaW9yKGdhbW1hKDAuMSwgMC4wMDAwMSksIGNsYXNzID0gc2hhcGUpLAogICAgICAgICAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMC4yNSksIGNsYXNzID0gYikpCgoKbV9wdWxtb25hcnlfcHJpb3IgPC0gYnJtKAogIHB1bG1vbmFyeV9ub3RpZmljYXRpb25zIH4geV9udW0gKyBhY2ZfcGVyaW9kICsgYWNmX3BlcmlvZDp5X251bSArICBvZmZzZXQobG9nKHRvdGFsX3BvcHVsYXRpb24pKSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IG1kYXRhMSwKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsCiAgICAgICAgICAgICAgICAgIGNoYWlucyA9IDQsIGNvcmVzID0gNCwgCiAgICAgICAgICAgICAgICAgIHByaW9yID0gd2luZm9ybV9wcmlvciwKICAgICAgICAgICAgICAgICAgc2FtcGxlX3ByaW9yID0gIm9ubHkiLAogICAgICAgICAgICAgICAgICBiYWNrZW5kPSJjbWRzdGFuciIsCiAgICAgICAgICAgICAgICAgIHNhdmVfcGFycyA9IHNhdmVfcGFycyhhbGwgPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgd2FybXVwID0gMTAwMCkKCnN1bW1hcnkobV9wdWxtb25hcnlfcHJpb3IpCmNvbmRpdGlvbmFsX2VmZmVjdHMobV9wdWxtb25hcnlfcHJpb3IpCgpgYGAKCk5vdyBmaXQgdGhlIG1vZGVsIHdpdGggdGhlIHdlYWtseSBpbmZvcm1hdGl2ZSBwcmlvcnMKCgpgYGB7cn0KbV9wdWxtb25hcnlfb3ZlcmFsbCA8LSBicm0oCiAgcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMgfiB5X251bSArIGFjZl9wZXJpb2QgKyBhY2ZfcGVyaW9kOnlfbnVtICsgIG9mZnNldChsb2codG90YWxfcG9wdWxhdGlvbikpLAogICAgICAgICAgICAgICAgICBkYXRhID0gbWRhdGExLAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAogICAgICAgICAgICAgICAgICBzZWVkID0gMTIzNCwKICAgICAgICAgICAgICAgICAgY2hhaW5zID0gNCwgY29yZXMgPSA0LCAKICAgICAgICAgICAgICAgICAgcHJpb3IgPSB3aW5mb3JtX3ByaW9yLAogICAgICAgICAgICAgICAgICBzYXZlX3BhcnMgPSBzYXZlX3BhcnMoYWxsID0gVFJVRSksCiAgICAgICAgICAgICAgICAgIGJhY2tlbmQgPSAiY21kc3RhbnIiLAogICAgICAgICAgICAgICAgICB3YXJtdXAgPSAxMDAwKQoKc3VtbWFyeShtX3B1bG1vbmFyeV9vdmVyYWxsKQpwbG90KG1fcHVsbW9uYXJ5X292ZXJhbGwpCnBwX2NoZWNrKG1fcHVsbW9uYXJ5X292ZXJhbGwsIHR5cGU9J2VjZGZfb3ZlcmxheScpCgpgYGAKCiMjIyMgNy4yIFN1bW1hcmlzZSBjaGFuZ2UgaW4gQ05ScwoKU3VtbWFyaXNlIHRoZSBwb3N0ZXJpb3IKCmBgYHtyfQoKZjFiIDwtIHBsb3RfY291bnRlcmZhY3R1YWwobW9kZWxfZGF0YSA9IG1kYXRhMSwgbW9kZWwgPSBtX3B1bG1vbmFyeV9vdmVyYWxsLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gdG90YWxfcG9wdWxhdGlvbiwgb3V0Y29tZSA9IGluY19wdWxtXzEwMGssIGdyb3VwaW5nX3Zhcj1OVUxMKQogIApmMWIKYGBgCgpNYWtlIHRoaXMgaW50byBhIGZpZ3VyZQoKYGBge3J9CgpmMWEgPC0gc3RfYXNfc2YobGVmdF9qb2luKHdhcmRfaW5jLCBnbGFzZ293X3dhcmRzXzE5NTEpKSAlPiUKICBmaWx0ZXIodGJfdHlwZT09IlB1bG1vbmFyeSIpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NmKGFlcyhmaWxsPWluY18xMDBrKSkgKwogIGZhY2V0X3dyYXAoeWVhcn4uLCBuY29sID0gNykgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG5hbWU9IkNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKHBlciAxMDAsMDAwKSIsCiAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9uID0gIkEiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgI2xlZ2VuZC5rZXkud2lkdGggPSB1bml0KDIsICJjbSIpLAogICAgICAgIGxlZ2VuZC50aXRsZS5hbGlnbiA9IDAuNSkgKwogIGd1aWRlcyhmaWxsPWd1aWRlX2NvbG9yYmFyKHRpdGxlLnBvc2l0aW9uID0gInRvcCIpKQoKKGYxYSAvIGYxYikgKyBwbG90X2Fubm90YXRpb24odGFnX2xldmVscyA9ICJBIikKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL2YxLnBuZyIpKQoKYGBgCgoKU3VtbWFyeSBvZiBjaGFuZ2UgaW4gbm90aWZpY2F0aW9ucwoKYGBge3J9CgpzdW1tYXJpc2VfY2hhbmdlKG1vZGVsX2RhdGE9bWRhdGExLCBtb2RlbD1tX3B1bG1vbmFyeV9vdmVyYWxsLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yPXRvdGFsX3BvcHVsYXRpb24sIGdyb3VwaW5nX3Zhcj1OVUxMKSAlPiUKICBtYXAoZGF0YXRhYmxlKQoKYGBgCihBbHRlcm5hdGl2ZSB3YXkgLSBrZWVwIGluIGZvciBub3cpCgpgYGB7cn0KCm92ZXJhbGxfaW1tZWRpYXRlX2RyYXdzIDwtIG1kYXRhMSAlPiUKICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhY2ZfcGVyaW9kLCB0b3RhbF9wb3B1bGF0aW9uLCBwdWxtb25hcnlfbm90aWZpY2F0aW9ucykgJT4lCiAgZmlsdGVyKHllYXIgJWluJSBjKDE5NTYsMTk1NykpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX3B1bG1vbmFyeV9vdmVyYWxsKSAlPiUKICBtdXRhdGUoaW5jXzEwMGsgPSAuZXByZWQvdG90YWxfcG9wdWxhdGlvbioxMDAwMDApICU+JQogIGdyb3VwX2J5KC5kcmF3KSAlPiUKICBzdW1tYXJpc2UocGN0X2NoYW5nZV9pbW1lZGlhdGUgPSAobGFzdChpbmNfMTAwaykgLSBmaXJzdChpbmNfMTAwaykpL2ZpcnN0KGluY18xMDBrKSkgJT4lCiAgdW5ncm91cCgpCgpvdmVyYWxsX3Bvc3RfZHJhd3MgPC0gbWRhdGExICU+JQogIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QsIHRvdGFsX3BvcHVsYXRpb24sIHB1bG1vbmFyeV9ub3RpZmljYXRpb25zKSAlPiUKICBmaWx0ZXIoeWVhciAlaW4lIGMoMTk1NiwxOTU4KSkgJT4lCiAgYWRkX2VwcmVkX2RyYXdzKG1fcHVsbW9uYXJ5X292ZXJhbGwpICU+JQogIG11dGF0ZShpbmNfMTAwayA9IC5lcHJlZC90b3RhbF9wb3B1bGF0aW9uKjEwMDAwMCkgJT4lCiAgZ3JvdXBfYnkoLmRyYXcpICU+JQogIHN1bW1hcmlzZShwY3RfY2hhbmdlX3Bvc3QgPSAobGFzdChpbmNfMTAwaykgLSBmaXJzdChpbmNfMTAwaykpL2ZpcnN0KGluY18xMDBrKSkgJT4lCiAgdW5ncm91cCgpCgoKb3ZlcmFsbF9zbG9wZV9kcmF3cyA8LSBtZGF0YTEgJT4lCiAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWNmX3BlcmlvZCwgdG90YWxfcG9wdWxhdGlvbiwgcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMpICU+JQogIGZpbHRlcih5ZWFyICVpbiUgYygxOTUwLCAxOTU2LCAxOTU4LCAxOTYzKSkgJT4lCiAgYWRkX2VwcmVkX2RyYXdzKG1fcHVsbW9uYXJ5X292ZXJhbGwpICU+JQogIG11dGF0ZShpbmNfMTAwayA9IC5lcHJlZC90b3RhbF9wb3B1bGF0aW9uKjEwMDAwMCkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShuX3llYXJzID0gbGVuZ3RoKHllYXIpLCAuYnk9YWNmX3BlcmlvZCkgJT4lCiAgZ3JvdXBfYnkoYWNmX3BlcmlvZCwgLmRyYXcpICU+JQogIHN1bW1hcmlzZShwY3RfY2hhbmdlX3Nsb3BlID0gKChsYXN0KGluY18xMDBrKSAtIGZpcnN0KGluY18xMDBrKSkvZmlyc3QoaW5jXzEwMGspKS9uX3llYXJzKSAlPiUKICBkaXN0aW5jdCgpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBjKGFjZl9wZXJpb2QpLAogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gcGN0X2NoYW5nZV9zbG9wZSkgJT4lCiAgbXV0YXRlKHJhdGlvX2FubnVhbF9zbG9wZSA9IGBjLiBwb3N0LWFjZmAgLyBgYS4gcHJlLWFjZmApCgoKYGBgCgpDb3JyZWxhdGlvbiBiZXR3ZWVuIGltbWVkaWF0ZSBlZmZlY3QgYW5kIHBvc3QgZWZmZWN0IG9mIEFDRgoKYGBge3J9CgpsZWZ0X2pvaW4ob3ZlcmFsbF9pbW1lZGlhdGVfZHJhd3MsIG92ZXJhbGxfcG9zdF9kcmF3cykgJT4lCiAgZ2dwbG90KGFlcyh4PXBjdF9jaGFuZ2VfaW1tZWRpYXRlLCB5PXBjdF9jaGFuZ2VfcG9zdCkpICsKICBnZW9tX2hkcigKICAgIGFlcyhmaWxsID0gYWZ0ZXJfc3RhdChwcm9icykpLCAKICAgIGFscGhhID0gMSkgKwogICNnZW9tX2hkcl9wb2ludHMoYWVzKGNvbG91ciA9IGFmdGVyX3N0YXQocHJvYnMpKSwgc2l6ZT0wLjUpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZT1GQUxTRSwgY29sb3VyPSJibGFjayIsIGxpbmV3aWR0aD0wLjUpICsKICBzdGF0X3JlZ2xpbmVfZXF1YXRpb24obGFiZWwueCA9IDAuMjUsIGxhYmVsLnkgPSAtMC4yNSwgc2l6ZT00KSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnQsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHByZXR0eV9icmVha3MobiA9IDEwKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50LAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBwcmV0dHlfYnJlYWtzKG4gPSA1KSkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKG9wdGlvbj0iRSIsIG5hbWU9IiIpICsKICBsYWJzKHRpdGxlPSJDb3JyZWxhdGlvbiBiZXR3ZWVuIGltbWVkaWF0ZSBBQ0YgaW1wYWN0IGFuZCBwb3N0LUFDRiBjYXNlIG5vdGlmaWNhdGlvbiByYXRlIiwKICAgICAgIHk9IlBvc3QgaW50ZXJ2ZW50aW9uIGltcGFjdDogZXJjZW50YWdlIGNoYW5nZSBpbiBDTlIgKDE5NTggdnMuIDE5NTYpIiwKICAgICAgIHg9IkltbWVkaWF0ZSBpbXBhY3Q6IHBlcmNlbnRhZ2UgY2hhbmdlIGluIENOUiAoMTk1NyB2cy4gMTk1NikiLAogICAgICAgY2FwdGlvbj0iQm91bmRhcmllcyBhcmUgcG9zdGVyaW9yIGRlc25pdHkgaW50ZXJ2YWxzIGZyb20gNDAwMCBkcmF3cyIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCgpgYGAKCkNvcnJlbGF0aW9uIGJldHdlZW4gaW1tZWRpYXRlIGVmZmVjdCBhbmQgY2hhbmdlIGluIHNsb3BlCgpgYGB7cn0KCmxlZnRfam9pbihvdmVyYWxsX2ltbWVkaWF0ZV9kcmF3cywgb3ZlcmFsbF9zbG9wZV9kcmF3cykgJT4lCiAgZ2dwbG90KGFlcyh4PXBjdF9jaGFuZ2VfaW1tZWRpYXRlLCB5PXJhdGlvX2FubnVhbF9zbG9wZSkpICsKICBnZW9tX2hkcigKICAgIGFlcyhmaWxsID0gYWZ0ZXJfc3RhdChwcm9icykpLCAKICAgIGFscGhhID0gMSkgKwogICNnZW9tX2hkcl9wb2ludHMoYWVzKGNvbG91ciA9IGFmdGVyX3N0YXQocHJvYnMpKSwgc2l6ZT0wLjUpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZT1GQUxTRSwgY29sb3VyPSJibGFjayIsIGxpbmV3aWR0aD0wLjUpICsKICAjc3RhdF9yZWdsaW5lX2VxdWF0aW9uKGxhYmVsLnggPSAwLjI1LCBsYWJlbC55ID0gMC4wMiwgc2l6ZT00KSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnQsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHByZXR0eV9icmVha3MobiA9IDEwKSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBwcmV0dHlfYnJlYWtzKG4gPSA1KSwKICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLCAxMCkpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZChvcHRpb249IkUiLCBuYW1lPSIiKSArCiAgbGFicyh0aXRsZT0iQ29ycmVsYXRpb24gYmV0d2VlbiBpbW1lZGlhdGUgQUNGIGltcGFjdCBhbmQgcG9zdC1BQ0YgY2FzZSBub3RpZmljYXRpb24gcmF0ZSIsCiAgICAgICB5PSJQb3N0IGludGVydmVudGlvbiBpbXBhY3Q6IFBlcmNlbnRhZ2UgY2hhbmdlIGluIENOUiAoMTk1OCB2cy4gMTk1NikiLAogICAgICAgeD0iSW1tZWRpYXRlIGltcGFjdDogcGVyY2VudGFnZSBjaGFuZ2UgaW4gQ05SICgxOTU3IHZzLiAxOTU2KSIsCiAgICAgICBjYXB0aW9uPSJQb2ludHMgYXJlIGRyYXdzIGZyb20gcG9zdGVpb3IgZGlzdHJpYnV0aW9uIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKCmBgYAoKCkFub3RoZXIgd2F5CgoKYGBge3J9Cgphc19kcmF3c19kZihtX3B1bG1vbmFyeV9vdmVyYWxsKQoKYGBgCgoKCiMjIyMgNy4zIENvbXBhcmVkIHRvIGNvdW50ZXJmYWN0dWFsCgpgYGB7cn0KCm92ZXJhbGxfcHVsbW9uYXJ5X2NvdW50ZXJmIDwtIGNhbGN1YXRlX2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBtZGF0YTEsIG1vZGVsPW1fcHVsbW9uYXJ5X292ZXJhbGwsIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSB0b3RhbF9wb3B1bGF0aW9uKQoKb3ZlcmFsbF9wdWxtb25hcnlfY291bnRlcmYgJT4lCiAgbWFwKGRhdGF0YWJsZSkKCgpgYGAKClRvdGFsIHB1bG1vbmFyeSBUQiBjYXNlcyBhdmVydGVkIGJldHdlZW4gMTk1OCBhbmQgMTk2MwoKYGBge3J9CgpvdmVyYWxsX3B1bG1vbmFyeV9jb3VudGVyZiRjb3VudGVyX3Bvc3QgJT4lCiAgc3VtbWFyaXNlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQsIGNhc2VzX2F2ZXJ0ZWQubG93ZXIsIGNhc2VzX2F2ZXJ0ZWQudXBwZXIpLCBzdW0pKQoKCmBgYAoKCgojIyMgOC4gRXh0cmEtcHVsbW9uYXJ5IFRCIG5vdGlmaWNhdGlvbnMKCiMjIyMgOC4xIEZpdCB0aGUKCmBgYHtyLCBtZXNzYWdlPUYsIHdhcm5pbmc9RkFMU0V9CgptX2V4dHJhcF9vdmVyYWxsIDwtIGJybSgKICBleHRyYXB1bG1vbmFyeV9ub3RpZmljYXRpb25zIH4geV9udW0gKyBhY2ZfcGVyaW9kICsgYWNmX3BlcmlvZDp5X251bSArb2Zmc2V0KGxvZyh0b3RhbF9wb3B1bGF0aW9uKSksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBtZGF0YTEsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IHBvaXNzb24oKSwKICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsCiAgICAgICAgICAgICAgICAgIGNoYWlucyA9IDQsIGNvcmVzID0gNCwgCiAgICAgICAgICAgICAgICAgIHByaW9yID0gYmFzaWNfcHJpb3IsCiAgICAgICAgICAgICAgICAgIHNhdmVfcGFycyA9IHNhdmVfcGFycyhhbGwgPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgYmFja2VuZCA9ICJjbWRzdGFuciIsCiAgICAgICAgICAgICAgICAgIHdhcm11cCA9IDEwMDApCgpzdW1tYXJ5KG1fZXh0cmFwX292ZXJhbGwpCnBsb3QobV9leHRyYXBfb3ZlcmFsbCkKcHBfY2hlY2sobV9leHRyYXBfb3ZlcmFsbCwgdHlwZT0nZWNkZl9vdmVybGF5JykKCmBgYAoKCmBgYHtyfQpwbG90X2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBtZGF0YTEsIG1vZGVsPW1fZXh0cmFwX292ZXJhbGwsIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSB0b3RhbF9wb3B1bGF0aW9uLCBvdXRjb21lPWluY19lcF8xMDBrKQogIApnZ3NhdmUoaGVyZSgiZmlndXJlcy9zNy5wbmciKSwgd2lkdGg9MTApCgpgYGAKCgojIyMjIDguMiBTdW1tYXJ5IG9mIGNoYW5nZQoKQS4gUGVyY2VudGFnZSBjaGFuZ2UgaW4gbW9ydGFsaXR5LCBmcm9tIDE5NTYgdG8gMTk1NyAoaS5lLiBpbW1lZGlhdGUgQUNGIGVmZmVjdCkKCmBgYHtyfQoKc3VtbWFyaXNlX2NoYW5nZShtb2RlbF9kYXRhPW1kYXRhMSwgbW9kZWwgPSBtX2V4dHJhcF9vdmVyYWxsLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gdG90YWxfcG9wdWxhdGlvbikgJT4lCiAgbWFwKGRhdGF0YWJsZSkKCmBgYAoKCgojIyMjIDguMyBDb21wYXJlZCB0byBjb3VudGVyZmFjdHVhbAoKYGBge3J9CgpvdmVyYWxsX2VwX2NvdW50ZXJmIDwtIGNhbGN1YXRlX2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBtZGF0YTEsIG1vZGVsPW1fZXh0cmFwX292ZXJhbGwsIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSB0b3RhbF9wb3B1bGF0aW9uKQoKb3ZlcmFsbF9lcF9jb3VudGVyZiAlPiUKICBtYXAoZGF0YXRhYmxlKQoKCmBgYAoKVG90YWwgZXh0cmEgcHVsbW9uYXJ5IFRCIGNhc2VzIGF2ZXJ0ZWQgYmV0d2VlbiAxOTU4IGFuZCAxOTYzCgpgYGB7cn0KCm92ZXJhbGxfZXBfY291bnRlcmYgJGNvdW50ZXJfcG9zdCAlPiUKICBzdW1tYXJpc2UoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZCwgY2FzZXNfYXZlcnRlZC5sb3dlciwgY2FzZXNfYXZlcnRlZC51cHBlciksIHN1bSkpCgoKYGBgCgoKIyMjIDkuIFdhcmQgbGV2ZWwgbW9kZWwKCiMjIyMgOS4xIEZpdCB0aGUgbW9kZWwKCmBgYHtyfQoKbWRhdGEyIDwtIHdhcmRfaW5jICU+JQogIGZpbHRlcih0Yl90eXBlPT0iUHVsbW9uYXJ5IikgJT4lCiAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oeWVhciAlaW4lIGMoMTk1MDoxOTU2KSB+ICJhLiBwcmUtYWNmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyICVpbiUgYygxOTU3KSB+ICJiLiBhY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTg6MTk2MykgfiAiYy4gcG9zdC1hY2YiKSkgJT4lCiAgZ3JvdXBfYnkod2FyZCkgJT4lCiAgbXV0YXRlKHlfbnVtID0gcm93X251bWJlcigpKSAlPiUKICB1bmdyb3VwKCkKCgoKYGBgCgooTm90ZSB0aGUgZGVub21pbmF0b3Igd2l0aG91dCBpbnN0aXR1dGlvbmFsaXNlZCBwZW9wbGUgYW5kICJzaGlwcGluZyIhKQoKYGBge3J9CiN3ZWFrbHkgaW5mb3JtYXRpdmUgcHJpb3JzIGZvciBtdWx0aWxldmVsIG1vZGVsCmJhc2ljX3ByaW9yMiA8LSBjKHByaW9yKG5vcm1hbCgwLCAxKSwgY2xhc3MgPSBJbnRlcmNlcHQpLAogICAgICAgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjEpLCBjbGFzcyA9IGIpLAogICAgICAgICAgICAgICAgIHByaW9yKGNhdWNoeSgwLDUpLCBjbGFzcz0ic2QiKSkKCgpnZ3Bsb3QoZGF0YSA9IHRpYmJsZSh4ID0gc2VxKGZyb20gPSAwLCB0byA9IDI1MCwgYnkgPSAxMCkpLAogICAgICAgYWVzKHggPSB4LCB5ID0gZGdhbW1hKHgsIHNoYXBlID0gMC41LCByYXRlID0gMC4wMSkpKSArCiAgZ2VvbV9hcmVhKGNvbG9yID0gInRyYW5zcGFyZW50IiwgCiAgICAgICAgICAgIGZpbGwgPSAiI0RFMEQ5MiIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoTlVMTCkgKwogIHNjYWxlX3lfY29udGludW91cyhOVUxMLCBicmVha3MgPSBOVUxMKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDI1MCkpICsKICBnZ3RpdGxlKGV4cHJlc3Npb24oYnJtc35+Z2FtbWEoMC41KiIsICIqMC4wMDAwMSl+c2hhcGV+cHJpb3IpKQoKd2luZm9ybV9wcmlvcjIgPC0gYyhwcmlvcihub3JtYWwoMCwgMSksIGNsYXNzID0gSW50ZXJjZXB0KSwKICAgICAgICAgICAgICAgICAgcHJpb3IoZ2FtbWEoMC41LCAwLjAxKSwgY2xhc3MgPSBzaGFwZSksCiAgICAgICAgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAxKSwgY2xhc3MgPSBiKSwKICAgICAgICAgICAgICAgICAgcHJpb3IoY2F1Y2h5KDAsNSksIGNsYXNzPSJzZCIpLAogICAgICAgICAgICAgICAgICBwcmlvcihsa2ooMiksIGNsYXNzPSJjb3IiKSkKYGBgCgoKYGBge3J9CgptX3B1bG1vbmFyeV93YXJkX3ByaW9yIDwtIGJybSgKICBjYXNlcyB+IHlfbnVtICsgYWNmX3BlcmlvZCArIGFjZl9wZXJpb2Q6eV9udW0gKyAoMSArIHlfbnVtICsgYWNmX3BlcmlvZCArIGFjZl9wZXJpb2Q6eV9udW0gfCB3YXJkKSArIG9mZnNldChsb2cocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCkpLAogICAgICAgICAgICAgICAgICBkYXRhID0gbWRhdGEyLAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAogICAgICAgICAgICAgICAgICBzZWVkID0gMTIzNCwKICAgICAgICAgICAgICAgICAgY2hhaW5zID0gNCwgY29yZXMgPSA0LCAKICAgICAgICAgICAgICAgICAgcHJpb3IgPSB3aW5mb3JtX3ByaW9yMiwKICAgICAgICAgICAgICAgICAgc2F2ZV9wYXJzID0gc2F2ZV9wYXJzKGFsbCA9IFRSVUUpLAogICAgICAgICAgICAgICAgICBzYW1wbGVfcHJpb3IgPSAib25seSIsCiAgICAgICAgICAgICAgICAgIGJhY2tlbmQgPSAiY21kc3RhbnIiLAogICAgICAgICAgICAgICAgICB3YXJtdXAgPSAxMDAwKQoKY29uZGl0aW9uYWxfZWZmZWN0cyhtX3B1bG1vbmFyeV93YXJkX3ByaW9yKQoKCmBgYAoKTm93IGZpdCB0aGUgbW9kZWwgd2l0aCBkYXRhCgpgYGB7cn0KbV9wdWxtb25hcnlfd2FyZCA8LSBicm0oCiAgY2FzZXMgfiB5X251bSArIGFjZl9wZXJpb2QgKyBhY2ZfcGVyaW9kOnlfbnVtICsgKDEgKyB5X251bSArIGFjZl9wZXJpb2QgKyBhY2ZfcGVyaW9kOnlfbnVtIHwgd2FyZCkgKyBvZmZzZXQobG9nKHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXApKSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IG1kYXRhMiwKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsCiAgICAgICAgICAgICAgICAgIGNoYWlucyA9IDQsIGNvcmVzID0gNCwgCiAgICAgICAgICAgICAgICAgIHByaW9yID0gd2luZm9ybV9wcmlvcjIsCiAgICAgICAgICAgICAgICAgIGJhY2tlbmQgPSAiY21kc3RhbnIiKQoKc3VtbWFyeShtX3B1bG1vbmFyeV93YXJkKQpwbG90KG1fcHVsbW9uYXJ5X3dhcmQpCnBwX2NoZWNrKG1fcHVsbW9uYXJ5X3dhcmQsIHR5cGU9J2VjZGZfb3ZlcmxheScpCgoKYGBgCgoKYGBge3J9CgpwbG90X2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBtZGF0YTIsIG1vZGVsPW1fcHVsbW9uYXJ5X3dhcmQsIG91dGNvbWUgPSBpbmNfMTAwaywgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIGdyb3VwaW5nX3ZhciA9IHdhcmQsIHdhcmQpCiAgCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3MzLnBuZyIpLCB3aWR0aD0xMCwgaGVpZ2h0PTEyKQoKYGBgCgojIyMjIDkuMiBTdW1tYXJ5IG9mIGNoYW5nZQoKQS4gcGVyY2VudGFnZSBpbmNyZWFzZSBpbiBDTlIsIGZyb20gMTk1NiB0byAxOTU3IChpLmUuIGltbWVkaWF0ZSBBQ0YgZWZmZWN0KQoKYGBge3J9Cgp3YXJkX2NoYW5nZSA8LSBzdW1tYXJpc2VfY2hhbmdlKG1vZGVsX2RhdGEgPSBtZGF0YTIsIG1vZGVsID0gbV9wdWxtb25hcnlfd2FyZCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIGdyb3VwaW5nX3Zhcj13YXJkKSAKCndhcmRfY2hhbmdlICU+JQogIG1hcChkYXRhdGFibGUpCgpgYGAKCkFzIGEgc3VwcGxlbWVudGFyeSBmaWd1cmUKCmBgYHtyfQogIAp3YXJkX2NoYW5nZSRpbW1lZGlhdGVfY2hhbmdlICU+JQogIGFycmFuZ2UoYWNmX2luYzEwMGtfcnIpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3BvaW50cmFuZ2UoYWVzKHk9YWNmX2luYzEwMGtfcnIsIHltaW49YWNmX2luYzEwMGtfcnIubG93ZXIsIHltYXg9YWNmX2luYzEwMGtfcnIudXBwZXIsIAogICAgICAgICAgICAgICAgICAgICAgeD1mY3RfcmVvcmRlcih3YXJkLCBhY2ZfaW5jMTAwa19yciksCiAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhY2ZfaW5jMTAwa19ycikpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0PTEpLCBsaW5ldHlwZT0yKSArCiAgY29vcmRfZmxpcCgpICsKICBzY2FsZV9jb2xvdXJfdmlyaWRpc19iKG9wdGlvbiA9ICJEIikgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAuOCwzLjApKSArCiAgbGFicyh4PSIiLAogICAgICAgeT0iUmVsYXRpdmUgcG9zdGVyaW9yIHByZWRpY3RlZCBjYXNlIG5vdGlmaWNhdGlvbiByYXRlIChwZXIgMTAwLDAwMDsgOTUlIFVJKVxuQUNGICgxOTU3KSB2cy4gQmVmb3JlIEFDRiAoMTk1NikiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQogIApnZ3NhdmUoaGVyZSgiZmlndXJlcy9zNC5wbmciKSkKCmBgYAoKCmBgYHtyfQoKd2FyZF9jaGFuZ2UkcG9zdF9jaGFuZ2UgJT4lCiAgYXJyYW5nZShhY2ZfaW5jMTAwa19ycikgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcG9pbnRyYW5nZShhZXMoeT1hY2ZfaW5jMTAwa19yciwgeW1pbj1hY2ZfaW5jMTAwa19yci5sb3dlciwgeW1heD1hY2ZfaW5jMTAwa19yci51cHBlciwgCiAgICAgICAgICAgICAgICAgICAgICB4PWZjdF9yZW9yZGVyKHdhcmQsIGFjZl9pbmMxMDBrX3JyKSwKICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFjZl9pbmMxMDBrX3JyKSkgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQ9MSksIGxpbmV0eXBlPTIpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX2NvbG91cl92aXJpZGlzX2Iob3B0aW9uID0gIkQiKSArCiAgI3NjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAuOCwzLjApKSArCiAgbGFicyh4PSIiLAogICAgICAgeT0iUmVsYXRpdmUgcG9zdGVyaW9yIHByZWRpY3RlZCBjYXNlIG5vdGlmaWNhdGlvbiByYXRlIChwZXIgMTAwLDAwMDsgOTUlIFVJKVxuQWZ0ZXIgQUNGICgxOTU4KSB2cy4gQmVmb3JlIEFDRiAoMTk1NikiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczUucG5nIikpCgoKYGBgCgoKcGVyY2VudGFnZSBjaGFuZ2UgPSAoZmluYWwgdmFsdWUgLSBpbml0aWFsIHZhbHVlKSAvIGluaXRpYWwgdmFsdWUKCmBgYHtyfQoKd2FyZF9jaGFuZ2Ukc2xvcGVfY2hhbmdlICU+JQogIGdncGxvdCgpICsKICBnZW9tX3BvaW50cmFuZ2UoYWVzKHk9cGN0X2NoYW5nZV9lcHJlZF9vdmVyYWxsICwgeW1pbj1wY3RfY2hhbmdlX2xvd2VyX292ZXJhbGwgLCB5bWF4PXBjdF9jaGFuZ2VfdXBwZXJfb3ZlcmFsbCAsCiAgICAgICAgICAgICAgICAgICAgICBncm91cD1hY2ZfcGVyaW9kLCBjb2xvdXI9YWNmX3BlcmlvZCwKICAgICAgICAgICAgICAgICAgICAgIHggPSBmY3RfcmVvcmRlcih3YXJkLCBwY3RfY2hhbmdlX2VwcmVkX292ZXJhbGwgKSkpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPXBlcmNlbnQpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiNERTBEOTIiLCAiIzRENkNGQSIpKSArCiAgI3NjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAuOCwzLjApKSArCiAgbGFicyh0aXRsZT0iSW50ZXJ2ZW50aW9uIGVmZmVjdCBvZiBtYXNzIG1pbmlhdHVyZSBjaGVzdCBYLXJheSBpbiBHbGFzZ293IiwKICAgICAgIHN1YnRpdGxlPSJCeSBtdW5pY2lwYWwgd2FyZCIsCiAgICAgICB4PSIiLAogICAgICAgeT0iTWVhbiBhbm51YWwgcmF0ZSBvZiBjaGFuZ2UgaW4gY2FzZSBub3RpZmljYXRpb24gcmF0ZSAoOTUlIENySSlcbiBCZWZvcmUgQUNGICgxOTUwLTE5NTYpIHZzLiBhZnRlciBBQ0YgKDE5NTgtMTk2MykiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgpgYGAKCihBbHRlcm5hdGl2ZSBmaWd1cmUgLSBrZWVwIGluIGZvciB0aGUgbWludXRlKQoKSXMgdGhlcmUgYW55IGNvcnJlbGF0aW9uIGJldHdlZW4gaW1tZWRpYXRlIGluY3JlYXNlIGFuZCBhKSBwb3N0LWludGVydmVudGlvbiAoMTk1OCkgZWZmZWN0LCBhbmQgYikgcG9zdCBpbnRlcnZlbnRpb24gc2xvcGUgKDE5NTgtMTk2MykKCmBgYHtyfQoKd2FyZF9jb3JzIDwtIHdhcmRfaW1wYWN0X291dCAlPiUKICBzZWxlY3Qod2FyZCwgaW1tZWRpYXRlX2VmZmVjdCA9IGFjZl9pbmMxMDBrX3JyLAogICAgICAgICAgICAgICBpbW1lZGlhdGVfZWZmZWN0X2xvd2VyID0gYWNmX2luYzEwMGtfcnIubG93ZXIsCiAgICAgICAgICAgICAgIGltbWVkaWF0ZV9lZmZlY3RfdXBwZXIgPSBhY2ZfaW5jMTAwa19yci51cHBlcikgJT4lCiAgcmlnaHRfam9pbigKICAgIHdhcmRfcHVsbV9pbXBhY3QyICU+JSAKICAgICAgc2VsZWN0KHdhcmQsIHBvc3RfZWZmZWN0ID0gYWNmX2luYzEwMGtfcnIsCiAgICAgICAgICAgICAgIHBvc3RfZWZmZWN0X2xvd2VyID0gYWNmX2luYzEwMGtfcnIubG93ZXIsCiAgICAgICAgICAgICAgIHBvc3RfZWZmZWN0X3VwcGVyID0gYWNmX2luYzEwMGtfcnIudXBwZXIpCiAgKSAlPiUKICByaWdodF9qb2luKAogICAgd2FyZF9wdWxtX2ltcGFjdDMgJT4lCiAgICAgIGZpbHRlcihhY2ZfcGVyaW9kPT0iYy4gcG9zdC1hY2YiKSAlPiUKICAgICAgc2VsZWN0KHdhcmQsIHNsb3BlX2VmZmVjdCA9IHBjdF9jaGFuZ2VfZXByZWRfYW5udWFsLAogICAgICAgICAgICAgc2xvcGVfZWZmZWN0X2xvd2VyID0gcGN0X2NoYW5nZV9sb3dlcl9hbm51YWwsCiAgICAgICAgICAgICBzbG9wZV9lZmZlY3RfdXBwZXIgPSBwY3RfY2hhbmdlX3VwcGVyX2FubnVhbCkKICApCgp3YXJkX2NvcnMgJT4lCiAgZ2dwbG90KGFlcyh4PWltbWVkaWF0ZV9lZmZlY3QsIHhtaW49aW1tZWRpYXRlX2VmZmVjdF9sb3dlciwgeG1heD1pbW1lZGlhdGVfZWZmZWN0X3VwcGVyLAogICAgICAgICAgICAgeT1wb3N0X2VmZmVjdCwgeW1pbj1wb3N0X2VmZmVjdF9sb3dlciwgeW1heD1wb3N0X2VmZmVjdF91cHBlciwKICAgICAgICAgICAgIGdyb3VwID0gd2FyZCkpICsKICBnZW9tX2Vycm9yYmFyKCkgKwogIGdlb21fZXJyb3JiYXJoKCkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICBsYWJzKHRpdGxlPSJDb3JyZWxhdGlvbiBiZXR3ZWVuIGltbWVkaWF0ZSBBQ0YgaW1wYWN0IGFuZCBwb3N0LUFDRiBjYXNlIG5vdGlmaWNhdGlvbiByYXRlIiwKICAgICAgIHk9IlJlbGF0aXZlIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKDE5NTggdnMuIDE5NTYpXG5Qb3N0IGludGVydmVudGlvbiBpbXBhY3QiLAogICAgICAgeD0iUmVsYXRpdmUgY2FzZSBub3RpZmljYXRpb24gcmF0ZSAoMTk1NyB2cy4gMTk1NilcbkltbWVkaWF0ZSBpbXBhY3QiLAogICAgICAgY2FwdGlvbj0iUG9pbnRzIGFyZSBtdW5pY2lwYWwgd2FyZHMiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgp3YXJkX2NvcnMgJT4lCiAgZ2dwbG90KGFlcyh4PWltbWVkaWF0ZV9lZmZlY3QsIHhtaW49aW1tZWRpYXRlX2VmZmVjdF9sb3dlciwgeG1heD1pbW1lZGlhdGVfZWZmZWN0X3VwcGVyLAogICAgICAgICAgICAgeT1zbG9wZV9lZmZlY3QsIHltaW49c2xvcGVfZWZmZWN0X2xvd2VyLCB5bWF4PXNsb3BlX2VmZmVjdF91cHBlciwKICAgICAgICAgICAgIGdyb3VwID0gd2FyZCkpICsKICBnZW9tX2Vycm9yYmFyKCkgKwogIGdlb21fZXJyb3JiYXJoKCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgbGFicyh0aXRsZT0iQ29ycmVsYXRpb24gYmV0d2VlbiBpbW1lZGlhdGUgQUNGIGltcGFjdCBhbmQgcG9zdC1BQ0YgbWVhbiByYXRlIG9mIGNoYW5nZSIsCiAgICAgICB5PSJQb3N0IEFDRiBtZWFuIGFubnVhbCByYXRlIG9mIGNoYW5nZSBpbiBjYXNlIG5vdGlmaWNhdGlvbiByYXRlcyIsCiAgICAgICB4PSJSZWxhdGl2ZSBjYXNlIG5vdGlmaWNhdGlvbiByYXRlICgxOTU3IHZzLiAxOTU2KVxuSW1tZWRpYXRlIGltcGFjdCIsCiAgICAgICBjYXB0aW9uPSJQb2ludHMgYXJlIG11bmljaXBhbCB3YXJkcyIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCgoKYGBgCgpUcnkgYSBkaWZmZXJlbnQgd2F5IHdpdGggdGhlIGZ1bGwgZGlzdHJpYnV0aW9uIG9mIHBvc3RlcmlvcnMKCgpgYGB7cn0KCndhcmRfaW1tZWRpYXRlX2RyYXdzIDwtIG1kYXRhMiAlPiUKICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhY2ZfcGVyaW9kLCBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBjYXNlcywgd2FyZCkgJT4lCiAgZmlsdGVyKHllYXIgJWluJSBjKDE5NTYsMTk1NykpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX3B1bG1vbmFyeV93YXJkKSAlPiUKICBtdXRhdGUoaW5jXzEwMGsgPSAuZXByZWQvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDApICU+JQogIGdyb3VwX2J5KHdhcmQsIC5kcmF3KSAlPiUKICBzdW1tYXJpc2UocGN0X2NoYW5nZV9pbW1lZGlhdGUgPSAobGFzdChpbmNfMTAwaykgLSBmaXJzdChpbmNfMTAwaykpL2ZpcnN0KGluY18xMDBrKSkgJT4lCiAgYXJyYW5nZSh3YXJkKSAlPiUKICB1bmdyb3VwKCkKCndhcmRfcG9zdF9kcmF3cyA8LSBtZGF0YTIgJT4lCiAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWNmX3BlcmlvZCwgcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgY2FzZXMsIHdhcmQpICU+JQogIGZpbHRlcih5ZWFyICVpbiUgYygxOTU2LDE5NTgpKSAlPiUKICBhZGRfZXByZWRfZHJhd3MobV9wdWxtb25hcnlfd2FyZCkgJT4lCiAgbXV0YXRlKGluY18xMDBrID0gLmVwcmVkL3BvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAqMTAwMDAwKSAlPiUKICBncm91cF9ieSh3YXJkLCAuZHJhdykgJT4lCiAgc3VtbWFyaXNlKHBjdF9jaGFuZ2VfcG9zdCA9IChsYXN0KGluY18xMDBrKSAtIGZpcnN0KGluY18xMDBrKSkvZmlyc3QoaW5jXzEwMGspKSAlPiUKICBhcnJhbmdlKHdhcmQpICU+JQogIHVuZ3JvdXAoKQoKCndhcmRfc2xvcGVfZHJhd3MgPC0gbWRhdGEyICU+JQogIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QsIHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIGNhc2VzLCB3YXJkKSAlPiUKICBmaWx0ZXIoeWVhciAlaW4lIGMoMTk1MCwgMTk1NiwgMTk1OCwgMTk2MykpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX3B1bG1vbmFyeV93YXJkKSAlPiUKICBtdXRhdGUoaW5jXzEwMGsgPSAuZXByZWQvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDApICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUobl95ZWFycyA9IGNhc2Vfd2hlbihhY2ZfcGVyaW9kPT0iYS4gcHJlLWFjZiIgfiA3LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2Q9PSJjLiBwb3N0LWFjZiIgfiA2KSkgJT4lCiAgZ3JvdXBfYnkod2FyZCwgYWNmX3BlcmlvZCwgLmRyYXcpICU+JQogIHN1bW1hcmlzZShwY3RfY2hhbmdlX3Nsb3BlID0gKChsYXN0KGluY18xMDBrKSAtIGZpcnN0KGluY18xMDBrKSkvZmlyc3QoaW5jXzEwMGspKS9uX3llYXJzKSAlPiUKICBkaXN0aW5jdCgpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBjKGFjZl9wZXJpb2QpLAogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gcGN0X2NoYW5nZV9zbG9wZSkgJT4lCiAgbXV0YXRlKHJhdGlvX2FubnVhbF9zbG9wZSA9IGBjLiBwb3N0LWFjZmAgLyBgYS4gcHJlLWFjZmApCiAgCgoKCgpgYGAKCgpDb3JyZWxhdGlvbiBiZXR3ZWVuIGltbWVkaWF0ZSBlZmZlY3QgYW5kIHBvc3QgZWZmZWN0IG9mIEFDRgoKYGBge3J9CgoKbGVmdF9qb2luKHdhcmRfaW1tZWRpYXRlX2RyYXdzLCB3YXJkX3Bvc3RfZHJhd3MpICU+JQogIGdncGxvdChhZXMoeD1wY3RfY2hhbmdlX2ltbWVkaWF0ZSwgeT1wY3RfY2hhbmdlX3Bvc3QsIGdyb3VwPXdhcmQpKSArCiAgZ2VvbV9oZHJfcG9pbnRzKHNpemU9MC4xKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2U9RkFMU0UsIGNvbG91cj0iYmxhY2siLCBsaW5ld2lkdGg9MC41KSArCiAgc3RhdF9yZWdsaW5lX2VxdWF0aW9uKGxhYmVsLnggPSAwLCBsYWJlbC55ID0gMC4yNSwgc2l6ZT00KSArCiAgc2NhbGVfY29sb3VyX3NjaWNvX2QocGFsZXR0ZSA9ICJsaXBhcmkiLCBuYW1lID0gIlBvc3RlcmlvciBwcm9iYWJpbGl0eSIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudCkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50KSArCiAgbGFicyh0aXRsZT0iQ29ycmVsYXRpb24gYmV0d2VlbiBpbW1lZGlhdGUgQUNGIGltcGFjdCBhbmQgcG9zdC1BQ0YgY2FzZSBub3RpZmljYXRpb24gcmF0ZSIsCiAgICAgICB5PSJQb3N0IGludGVydmVudGlvbiBpbXBhY3Q6IGVyY2VudGFnZSBjaGFuZ2UgaW4gQ05SICgxOTU4IHZzLiAxOTU2KSIsCiAgICAgICB4PSJJbW1lZGlhdGUgaW1wYWN0OiBwZXJjZW50YWdlIGNoYW5nZSBpbiBDTlIgKDE5NTcgdnMuIDE5NTYpIiwKICAgICAgIGNhcHRpb249IlBvaW50cyBhcmUgZHJhd3MgZnJvbSBwb3N0ZWlvciBkaXN0cmlidXRpb24iKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKICBmYWNldF93cmFwKHdhcmR+LikKCgpgYGAKCkNvcnJlbGF0aW9uIGJldHdlZW4gaW1tZWRpYXRlIGVmZmVjdCBhbmQgY2hhbmdlIGluIHNsb3BlCgpgYGB7cn0KCmxlZnRfam9pbih3YXJkX2ltbWVkaWF0ZV9kcmF3cywgd2FyZF9zbG9wZV9kcmF3cykgJT4lCiAgZ2dwbG90KGFlcyh4PXBjdF9jaGFuZ2VfaW1tZWRpYXRlLCB5PXJhdGlvX2FubnVhbF9zbG9wZSwgZ3JvdXA9d2FyZCkpICsKICBnZW9tX2hkcl9wb2ludHMoc2l6ZT0wLjEpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZT1GQUxTRSwgY29sb3VyPSJibGFjayIsIGxpbmV3aWR0aD0wLjUpICsKICAjc3RhdF9yZWdsaW5lX2VxdWF0aW9uKGxhYmVsLnggPSAwLCBsYWJlbC55ID0gMC4wMiwgc2l6ZT00KSArCiAgc2NhbGVfY29sb3VyX3NjaWNvX2QocGFsZXR0ZSA9ICJsaXBhcmkiLCBuYW1lID0gIlBvc3RlcmlvciBwcm9iYWJpbGl0eSIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudCkgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDEwKSkgKwogIGxhYnModGl0bGU9IkNvcnJlbGF0aW9uIGJldHdlZW4gaW1tZWRpYXRlIEFDRiBpbXBhY3QgYW5kIHBvc3QtQUNGIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUiLAogICAgICAgeT0iUG9zdCBpbnRlcnZlbnRpb24gaW1wYWN0OiBQZXJjZW50YWdlIGNoYW5nZSBpbiBDTlIgKDE5NTggdnMuIDE5NTYpIiwKICAgICAgIHg9IkltbWVkaWF0ZSBpbXBhY3Q6IHBlcmNlbnRhZ2UgY2hhbmdlIGluIENOUiAoMTk1NyB2cy4gMTk1NikiLAogICAgICAgY2FwdGlvbj0iUG9pbnRzIGFyZSBkcmF3cyBmcm9tIHBvc3RlaW9yIGRpc3RyaWJ1dGlvbiIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkgKwogIGZhY2V0X3dyYXAod2FyZH4uKQoKCmBgYAoKCkpvaW4gdGhlc2UgdG9nZXRoZXIgd2l0aCB0aGUgb3ZlcmFsbCBlc3RpbWF0ZXMgdG8gbWFrZSBhIHNpbmdsZSBmaWd1cmUgZm9yIHNob3dpbmcgaW1wYWN0CgpgYGB7cn0KCmYyX2RhdGEgPC0gCiAgbGVmdF9qb2luKG92ZXJhbGxfaW1tZWRpYXRlX2RyYXdzLCBvdmVyYWxsX3Bvc3RfZHJhd3MpICU+JQogIGxlZnRfam9pbihvdmVyYWxsX3Nsb3BlX2RyYXdzKSAlPiUKICBtdXRhdGUobGV2ZWwgPSAib3ZlcmFsbCIsCiAgICAgICAgIHdhcmQgPSAiR2xhc2dvdyIpICU+JQogIGJpbmRfcm93cygKICAgIGxlZnRfam9pbih3YXJkX2ltbWVkaWF0ZV9kcmF3cywgd2FyZF9wb3N0X2RyYXdzKSAlPiUKICBsZWZ0X2pvaW4od2FyZF9zbG9wZV9kcmF3cykgJT4lCiAgbXV0YXRlKGxldmVsID0gIndhcmQiKQogICkKCmYyYSA8LSBmMl9kYXRhICU+JSAKICBnZ3Bsb3QoYWVzKHg9cGN0X2NoYW5nZV9pbW1lZGlhdGUsIHk9cGN0X2NoYW5nZV9wb3N0LCBncm91cD13YXJkKSkgKwogIGdlb21faGRyX3BvaW50cyhzaXplPTAuMSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlPUZBTFNFLCBjb2xvdXI9ImJsYWNrIiwgbGluZXdpZHRoPTAuNSkgKwogIHN0YXRfcmVnbGluZV9lcXVhdGlvbihsYWJlbC54ID0gMCwgbGFiZWwueSA9IDAuMTIsIHNpemU9NCkgKwogIHNjYWxlX2NvbG91cl9zY2ljb19kKHBhbGV0dGUgPSAibGlwYXJpIiwgbmFtZSA9ICJQb3N0ZXJpb3IgcHJvYmFiaWxpdHkgZGVuc2l0eSIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudCkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50KSArCiAgbGFicyh5PSJQb3N0LWludGVydmVudGlvbiBpbXBhY3Q6IFBlcmNlbnRhZ2UgY2hhbmdlIGluIENOUiAoMTk1OCB2cy4gMTk1NikiLAogICAgICAgeD0iSW1tZWRpYXRlIGltcGFjdDogcGVyY2VudGFnZSBjaGFuZ2UgaW4gQ05SICgxOTU3IHZzLiAxOTU2KSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkgKwogIGZhY2V0X3dyYXAoZmN0X3JlbGV2ZWwod2FyZCwKICAgICAgICAgICAgICAgICAgICAgICAgICJHbGFzZ293IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFmdGVyPTApfi4sIG5jb2wgPSA1KSArIAogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTQpKSkKCmYyYQoKZjJiIDwtIGYyX2RhdGEgJT4lIAogIGdncGxvdChhZXMoeD1wY3RfY2hhbmdlX2ltbWVkaWF0ZSwgeT1yYXRpb19hbm51YWxfc2xvcGUsIGdyb3VwPXdhcmQpKSArCiAgZ2VvbV9oZHJfcG9pbnRzKHNpemU9MC4xKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2U9RkFMU0UsIGNvbG91cj0iYmxhY2siLCBsaW5ld2lkdGg9MC41KSArCiAgc3RhdF9yZWdsaW5lX2VxdWF0aW9uKGxhYmVsLnggPSAxLjIsIGxhYmVsLnkgPSAxMiwgc2l6ZT00KSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnQsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHByZXR0eV9icmVha3MobiA9IDQpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHByZXR0eV9icmVha3MobiA9IDQpLAogICAgICAgICAgICAgICAgbGltaXRzID0gYygwLDE1KSkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKG9wdGlvbj0iRSIpICsKICBsYWJzKHk9IlBvc3QtaW50ZXJ2ZW50aW9uIGltcGFjdDogUmVsYXRpdmUgY2hhbmdlIGluIGFubnVhbCBDTlIgc2xvcGUgKDE5NTgtMTk2MyB2cy4gMTk1MC0xOTU2KSIsCiAgICAgICB4PSJJbW1lZGlhdGUgaW1wYWN0OiBwZXJjZW50YWdlIGNoYW5nZSBpbiBDTlIgKDE5NTcgdnMuIDE5NTYpIiwKICAgICAgIGNvbG91cj0iUG9zdGVyaW9yIHByb2JhYmlsaXR5IGRlbnNpdHkiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKICBmYWNldF93cmFwKGZjdF9yZWxldmVsKHdhcmQsCiAgICAgICAgICAgICAgICAgICAgICAgICAiR2xhc2dvdyIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZnRlcj0wKX4uLCBuY29sID0gNSkgKyAKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSkpCgpmMmIKCihmMmEgLyBmMmIpICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAnQScpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9mMi5wbmciKSwgaGVpZ2h0PTE4LCB3aWR0aD0xMCkKCmBgYAoKIyMjIyA5LjMgQ29tcGFyZWQgdG8gY291bnRlcmZhY3R1YWwKCmBgYHtyfQoKd2FyZF9jb3VudGVyZiA8LSBjYWxjdWF0ZV9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gbWRhdGEyLCBtb2RlbD1tX3B1bG1vbmFyeV93YXJkLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgZ3JvdXBpbmdfdmFyPXdhcmQpCgp3YXJkX2NvdW50ZXJmICU+JQogIG1hcChkYXRhdGFibGUpCgoKYGBgCgpUb3RhbCBwdWxtb25hcnkgVEIgY2FzZXMgYXZlcnRlZCBiZXR3ZWVuIDE5NTggYW5kIDE5NjMKCmBgYHtyfQoKd2FyZF9jb3VudGVyZiRjb3VudGVyX3Bvc3QgJT4lCiAgc3VtbWFyaXNlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQsIGNhc2VzX2F2ZXJ0ZWQubG93ZXIsIGNhc2VzX2F2ZXJ0ZWQudXBwZXIpLCBzdW0pLCAuYnk9d2FyZCkKCgpgYGAKCiMjIyAxMC4gQWdlLXNleCBtb2RlbAoKRml0IHRoZSBtb2RlbAoKKE5vdCByZXdyaXR0ZW4gdGhlIGZ1bmN0aW9ucyBmb3IgdGhpcyB5ZXQpCgpgYGB7cn0KCm1kYXRhMyA8LSBjYXNlc19ieV9hZ2Vfc2V4ICU+JQogIGZpbHRlcih0Yl90eXBlPT0iUHVsbW9uYXJ5IikgJT4lCiAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oeWVhciAlaW4lIGMoMTk1MDoxOTU2KSB+ICJhLiBwcmUtYWNmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyICVpbiUgYygxOTU3KSB+ICJiLiBhY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTg6MTk2MykgfiAiYy4gcG9zdC1hY2YiKSkgJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpICU+JQogIGdyb3VwX2J5KGFnZSwgc2V4KSAlPiUKICBtdXRhdGUoeV9udW0gPSByb3dfbnVtYmVyKCkpICU+JQogIHVuZ3JvdXAoKQoKd2luZm9ybV9wcmlvcjMgPC0gYyhwcmlvcihub3JtYWwoMCwgMSksIGNsYXNzID0gSW50ZXJjZXB0KSwKICAgICAgICAgICAgICAgICAgI3ByaW9yKGdhbW1hKDAuNSwgMC4wMSksIGNsYXNzID0gc2hhcGUpLAogICAgICAgICAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMSksIGNsYXNzID0gYiksCiAgICAgICAgICAgICAgICAgIHByaW9yKGNhdWNoeSgwLDUpLCBjbGFzcz0ic2QiKSwKICAgICAgICAgICAgICAgICAgcHJpb3IobGtqKDIpLCBjbGFzcz0iY29yIikpCgoKbV9hZ2Vfc2V4IDwtIGJybSgKICBjYXNlcyB+IHlfbnVtICsgKGFjZl9wZXJpb2QpKihhZ2Uqc2V4KSArIChhY2ZfcGVyaW9kOnlfbnVtKSooYWdlKnNleCksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBtZGF0YTMsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0LAogICAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LCBjb3JlcyA9IDQsIAogICAgICAgICAgICAgICAgICBwcmlvciA9IGJhc2ljX3ByaW9yLAogICAgICAgICAgICAgICAgICBiYWNrZW5kID0gImNtZHN0YW5yIikKCnN1bW1hcnkobV9hZ2Vfc2V4KQpwbG90KG1fYWdlX3NleCkKcHBfY2hlY2sobV9hZ2Vfc2V4LCB0eXBlPSdlY2RmX292ZXJsYXknKQoKCmBgYAoKU3VtbWFyaXNlIHBvc3RlcmlvcgoKYGBge3J9CgojcG9zdGVyaW9yIGRyYXdzLCBhbmQgc3VtbWFyaXNlCmFnZV9zZXhfc3VtbWFyeSA8LSBtZGF0YTMgJT4lCiAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWNmX3BlcmlvZCwgYWdlLCBzZXgpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX2FnZV9zZXgpICU+JQogIGdyb3VwX2J5KHllYXIyLCBhY2ZfcGVyaW9kLCBhZ2UsIHNleCkgJT4lCiAgbWVhbl9xaSgpICU+JQogIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKGFjZl9wZXJpb2Q9PSJhLiBwcmUtYWNmIiB+ICJCZWZvcmUgSW50ZXJ2ZW50aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kPT0iYy4gcG9zdC1hY2YiIH4gIlBvc3QgSW50ZXJ2ZW50aW9uIikpCgojY3JlYXRlIHRoZSBjb3VudGVyZmFjdHVhbCAobm8gaW50ZXJ2ZW50aW9uKSwgYW5kIHN1bW1hcmlzZQphZ2Vfc2V4X2NvdW50ZXJmYWN0IDwtIAogIHRpYmJsZSh5ZWFyID0gbWRhdGEzJHllYXIsCiAgICAgICAgIHllYXIyID0gbWRhdGEzJHllYXIyLAogICAgICAgICB5X251bSA9IG1kYXRhMyR5X251bSwKICAgICAgICAgYWdlID0gbWRhdGEzJGFnZSwKICAgICAgICAgc2V4ID0gbWRhdGEzJHNleCwKICAgICAgICAgYWNmX3BlcmlvZCA9IGZhY3RvcigiYS4gcHJlLWFjZiIpKSAlPiUKICBhZGRfZXByZWRfZHJhd3MobV9hZ2Vfc2V4KSAlPiUKICBncm91cF9ieSh5ZWFyMiwgYWNmX3BlcmlvZCwgYWdlLCBzZXgpICU+JQogIG1lYW5fcWkoKSAlPiUKICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbihhY2ZfcGVyaW9kPT0iYS4gcHJlLWFjZiIgfiAiQmVmb3JlIEludGVydmVudGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZD09ImMuIHBvc3QtYWNmIiB+ICJQb3N0IEludGVydmVudGlvbiIpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2U9PSIwMF8wNSIgfiAiMCB0byA1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIwNl8xNSIgfiAiMDYgdG8gMTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjE2XzI1IiB+ICIxNiB0byAyNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMjZfMzUiIH4gIjI2IHRvIDM1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIzNl80NSIgfiAiMzYgdG8gNDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjQ2XzU1IiB+ICI0NiB0byA1NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNTZfNjUiIH4gIjU2IHRvIDY1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI2NSsiIH4gIjY1ICYgdXAgeSIpKSAlPiUKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09ICJNIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09ICJGIiB+ICJGZW1hbGUiKSkgCgoKCmFnZV9zZXhfc3VtbWFyeSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2U9PSIwMF8wNSIgfiAiMCB0byA1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIwNl8xNSIgfiAiMDYgdG8gMTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjE2XzI1IiB+ICIxNiB0byAyNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMjZfMzUiIH4gIjI2IHRvIDM1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIzNl80NSIgfiAiMzYgdG8gNDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjQ2XzU1IiB+ICI0NiB0byA1NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNTZfNjUiIH4gIjU2IHRvIDY1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI2NSsiIH4gIjY1ICYgdXAgeSIpKSAlPiUKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09ICJNIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09ICJGIiB+ICJGZW1hbGUiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcmliYm9uKGFlcyh5bWluPS5lcHJlZC5sb3dlciwgeW1heD0uZXByZWQudXBwZXIsIHg9eWVhcjIsIGdyb3VwID0gYWNmX3BlcmlvZCwgZmlsbD1hY2ZfcGVyaW9kKSwgYWxwaGE9MC41KSArCiAgZ2VvbV9yaWJib24oZGF0YSA9IGFnZV9zZXhfY291bnRlcmZhY3QgJT4lIGZpbHRlcih5ZWFyPj0xOTU2KSwgCiAgICAgICAgICAgICAgYWVzKHltaW49LmVwcmVkLmxvd2VyLCB5bWF4PS5lcHJlZC51cHBlciwgeD15ZWFyMiwgZmlsbD0iQ291bnRlcmZhY3R1YWwiKSwgYWxwaGE9MC41KSArCiAgZ2VvbV9saW5lKGRhdGEgPSBhZ2Vfc2V4X2NvdW50ZXJmYWN0ICU+JSBmaWx0ZXIoeWVhcj49MTk1NiksIAogICAgICAgICAgICAgIGFlcyh5PS5lcHJlZCwgeD15ZWFyMiwgY29sb3VyPSJDb3VudGVyZmFjdHVhbCIpKSArCiAgZ2VvbV9saW5lKGFlcyh5PS5lcHJlZCwgeD15ZWFyMiwgZ3JvdXA9YWNmX3BlcmlvZCwgIGNvbG91cj1hY2ZfcGVyaW9kKSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IG1kYXRhMyAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2U9PSIwMF8wNSIgfiAiMCB0byA1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIwNl8xNSIgfiAiMDYgdG8gMTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjE2XzI1IiB+ICIxNiB0byAyNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMjZfMzUiIH4gIjI2IHRvIDM1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIzNl80NSIgfiAiMzYgdG8gNDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjQ2XzU1IiB+ICI0NiB0byA1NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNTZfNjUiIH4gIjU2IHRvIDY1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI2NSsiIH4gIjY1ICYgdXAgeSIpKSAlPiUKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09ICJNIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09ICJGIiB+ICJGZW1hbGUiKSkgLCBhZXMoeT1jYXNlcywgeD15ZWFyMiwgc2hhcGU9YWNmX3BlcmlvZCksIHNpemU9MikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBnZ2g0eDo6ZmFjZXRfZ3JpZDIoYWdlfnNleCwgc2NhbGVzID0gImZyZWVfeSIsIGluZGVwZW5kZW50ID0gInkiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjREUwRDkyIiwgImdyZXk1MCIsICIjNEQ2Q0ZBIikgLCBuYW1lPSIiKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjREUwRDkyIiwgImdyZXk1MCIsICIjNEQ2Q0ZBIikgLCBuYW1lPSIiKSArCiAgc2NhbGVfc2hhcGVfZGlzY3JldGUobmFtZT0iIikgKwogIGxhYnMoCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJDYXNlIG5vdGlmaWNhdGlvbnMgKG4pIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1NykiCiAgKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSwKICAgICAgICB0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMikpICsKICBndWlkZXMoc2hhcGU9Im5vbmUiKQogIApnZ3NhdmUoaGVyZSgiZmlndXJlcy9zNi5wbmciKSwgaGVpZ2h0PTEwKQoKYGBgCgpTdW1tYXJ5IG9mIGltcGFjdCBvZiBpbnRlcnZlbnRpb24KCjEuIHBlcmNlbnRhZ2UgaW5jcmVhc2UgaW4gQ05SLCBmcm9tIDE5NTYgdG8gMTk1NyAoaS5lLiBpbW1lZGlhdGUgQUNGIGVmZmVjdCkKCmBgYHtyfQoKbmQgPC0gbWRhdGEzICU+JQogIGZpbHRlcih5ZWFyICVpbiUgYygxOTU2OjE5NTcpKSAlPiUKICBzZWxlY3QoYWNmX3BlcmlvZCwgeV9udW0sIGFnZSwgc2V4KQoKCmFnZV9zZXhfaW1wYWN0X291dCA8LSAKICBhZGRfZXByZWRfZHJhd3MobV9hZ2Vfc2V4LAogICAgICAgICAgICAgICAgbmV3ZGF0YT1uZCkgJT4lCiAgdW5ncm91cCgpICU+JQogIHNlbGVjdChhY2ZfcGVyaW9kLCAuZXByZWQsIGFnZSwgc2V4KSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gYWNmX3BlcmlvZCwKICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IC5lcHJlZCwKICAgICAgICAgICAgICB2YWx1ZXNfZm4gPSBsaXN0KSAlPiUKICB1bm5lc3QoKSAlPiUKICByZW5hbWUocHJlX2VwcmVkID0gMywKICAgICAgICAgcG9zdF9lcHJlZCA9IDQpICU+JQogIG11dGF0ZShhY2ZfZGlmZiA9IHBvc3RfZXByZWQtcHJlX2VwcmVkLAogICAgICAgICBhY2ZfcnIgPSBwb3N0X2VwcmVkL3ByZV9lcHJlZCkgJT4lCiAgZ3JvdXBfYnkoYWdlLCBzZXgpICU+JQogIG1lYW5fcWkoYWNmX2RpZmYsIGFjZl9ycikgCgphZ2Vfc2V4X2ltcGFjdF9vdXQgJT4lCiAgbXV0YXRlX2lmKGlzLmRvdWJsZSwgfiBzY2FsZXM6Om51bWJlcih4ID0gLiwgYWNjdXJhY3kgPSAwLjAxLCBiaWcubWFyayA9ICIsIikpICU+JQogIGRhdGF0YWJsZSgpCiAgCmYzYSA8LSBhZ2Vfc2V4X2ltcGFjdF9vdXQgJT4lCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXg9PSJNIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09IkYiIH4gIkZlbWFsZSIpKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZT09IjAwXzA1IiB+ICIwIHRvIDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjA2XzE1IiB+ICIwNiB0byAxNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMTZfMjUiIH4gIjE2IHRvIDI1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIyNl8zNSIgfiAiMjYgdG8gMzV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjM2XzQ1IiB+ICIzNiB0byA0NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNDZfNTUiIH4gIjQ2IHRvIDU1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI1Nl82NSIgfiAiNTYgdG8gNjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjY1KyIgfiAiNjUgJiB1cCB5IikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3BvaW50cmFuZ2UoYWVzKHk9YWNmX3JyLCB5bWluPWFjZl9yci5sb3dlciwgeW1heD1hY2ZfcnIudXBwZXIsIGdyb3VwPXNleCwgCiAgICAgICAgICAgICAgICAgICAgICB4PWFnZSwKICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNleCksCiAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjI1KSkgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQ9MSksIGxpbmV0eXBlPTIpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoInB1cnBsZSIsICJkYXJrb3JhbmdlIiksIG5hbWU9IiIpICsKICBsYWJzKHg9IiIsCiAgICAgICB5PSJSZWxhdGl2ZSBub3RpZmljYXRpb25zICg5NSUgVUkpXG5BQ0YgKDE5NTcpIHZzLiBCZWZvcmUgQUNGICgxOTU2KSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKICAKICAKCmBgYAoKCjIuIENoYW5nZSBmcm9tIHByZS1BQ0YgcGVyaW9kICgxOTU2KSwgdG8gZmlyc3QgeWVhciBwb3N0LUFDRiAoMTk1OCkKCgpgYGB7cn0KCm5kIDwtIG1kYXRhMyAlPiUKICBmaWx0ZXIoeWVhciAlaW4lIGMoMTk1NiwxOTU4KSkgJT4lCiAgc2VsZWN0KGFjZl9wZXJpb2QsIHlfbnVtLCBhZ2UsIHNleCkKCiNEbyBpdCB3aXRoIGNhbGN1bGF0aW5nIGluY2lkZW5jZSwgdGhlbiBzdW1hbXJpc2luZy4KYWdlX3NleF9pbXBhY3QyIDwtYWRkX2VwcmVkX2RyYXdzKG1fYWdlX3NleCwKICAgICAgICAgICAgICAgIG5ld2RhdGE9bmQpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzZWxlY3QoYWNmX3BlcmlvZCwgLmVwcmVkLCBhZ2UsIHNleCkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGFjZl9wZXJpb2QsCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSAuZXByZWQsCiAgICAgICAgICAgICAgdmFsdWVzX2ZuID0gbGlzdCkgJT4lCiAgdW5uZXN0KCkgJT4lCiAgcmVuYW1lKHByZV9lcHJlZCA9IDMsCiAgICAgICAgcG9zdF9lcHJlZCA9IDQpICU+JQogIG11dGF0ZShhY2ZfZGlmZiA9IHBvc3RfZXByZWQtcHJlX2VwcmVkLAogICAgICAgICBhY2ZfcnIgPSBwb3N0X2VwcmVkL3ByZV9lcHJlZCkgJT4lCiAgZ3JvdXBfYnkoYWdlLCBzZXgpICU+JQogIG1lYW5fcWkoYWNmX2RpZmYsIGFjZl9ycikgCgphZ2Vfc2V4X2ltcGFjdDIgJT4lCiAgbXV0YXRlX2lmKGlzLmRvdWJsZSwgfiBzY2FsZXM6Om51bWJlcih4ID0gLiwgYWNjdXJhY3kgPSAwLjAxLCBiaWcubWFyayA9ICIsIikpICU+JQogIGRhdGF0YWJsZSgpCgpmM2IgPC0gYWdlX3NleF9pbXBhY3QyICU+JSAgCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXg9PSJNIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09IkYiIH4gIkZlbWFsZSIpKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZT09IjAwXzA1IiB+ICIwIHRvIDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjA2XzE1IiB+ICIwNiB0byAxNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMTZfMjUiIH4gIjE2IHRvIDI1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIyNl8zNSIgfiAiMjYgdG8gMzV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjM2XzQ1IiB+ICIzNiB0byA0NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNDZfNTUiIH4gIjQ2IHRvIDU1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI1Nl82NSIgfiAiNTYgdG8gNjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjY1KyIgfiAiNjUgJiB1cCB5IikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3BvaW50cmFuZ2UoYWVzKHk9YWNmX3JyLCB5bWluPWFjZl9yci5sb3dlciwgeW1heD1hY2ZfcnIudXBwZXIsIGdyb3VwPXNleCwgCiAgICAgICAgICAgICAgICAgICAgICB4PWFnZSwKICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNleCksCiAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjI1KSkgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQ9MSksIGxpbmV0eXBlPTIpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoInB1cnBsZSIsICJkYXJrb3JhbmdlIiksIG5hbWU9IiIpICsKICBsYWJzKHg9IiIsCiAgICAgICB5PSJSZWxhdGl2ZSBub3RpZmljYXRpb25zICg5NSUgVUkpXG5BQ0YgKDE5NTgpIHZzLiBCZWZvcmUgQUNGICgxOTU2KSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCgpgYGAKCjMuIENoYW5nZSBpbiBzbG9wZSAoaS5lLiBkaWZmZXJlbmNlIGluIG1lYW4gYW5udWFsIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgcHJlLUludGVydmVudGlvbiB2cy4gcG9zdC1pbnRlcnZlbnRpb24sIGJ5IHdhcmQpCgpgYGB7cn0KCmFnZV9zZXhfaW1wYWN0MyA8LSBtZGF0YTMgJT4lCiAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWNmX3BlcmlvZCwgY2FzZXMsIGFnZSwgc2V4KSAlPiUKICBmaWx0ZXIoeWVhciE9MTk1NykgJT4lCiAgYWRkX2VwcmVkX2RyYXdzKG1fYWdlX3NleCkgJT4lCiAgZ3JvdXBfYnkoeWVhciwgYWdlLCBzZXgsIGFjZl9wZXJpb2QpICU+JQogIG1lYW5fcWkoLmVwcmVkKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKG5feWVhcnMgPSBsZW5ndGgoeWVhciksIC5ieT1hY2ZfcGVyaW9kKSAlPiUKICBzdW1tYXJpc2UocGN0X2NoYW5nZV9lcHJlZF9vdmVyYWxsID0gKCgobGFzdCguZXByZWQpIC0gZmlyc3QoLmVwcmVkKSkvZmlyc3QoLmVwcmVkKSkpLAogICAgICAgICAgICBwY3RfY2hhbmdlX2xvd2VyX292ZXJhbGwgPSAoKChsYXN0KC5sb3dlcikgLSBmaXJzdCgubG93ZXIpKS9maXJzdCgubG93ZXIpKSksCiAgICAgICAgICAgIHBjdF9jaGFuZ2VfdXBwZXJfb3ZlcmFsbCA9ICgoKGxhc3QoLnVwcGVyKSAtIGZpcnN0KC51cHBlcikpL2ZpcnN0KC51cHBlcikpKSwKICAgIAogICAgICAgICAgICBwY3RfY2hhbmdlX2VwcmVkX2FubnVhbCA9ICgoKGxhc3QoLmVwcmVkKSAtIGZpcnN0KC5lcHJlZCkpL2ZpcnN0KC5lcHJlZCkpL25feWVhcnMpLAogICAgICAgICAgICBwY3RfY2hhbmdlX2xvd2VyX2FubnVhbCA9ICgoKGxhc3QoLmxvd2VyKSAtIGZpcnN0KC5sb3dlcikpL2ZpcnN0KC5sb3dlcikpL25feWVhcnMpLAogICAgICAgICAgICBwY3RfY2hhbmdlX3VwcGVyX2FubnVhbCA9ICgoKGxhc3QoLnVwcGVyKSAtIGZpcnN0KC51cHBlcikpL2ZpcnN0KC51cHBlcikpL25feWVhcnMpLAogICAgICAgICAgICAuYnkgPSBjKGFjZl9wZXJpb2QsIGFnZSwgc2V4KSkgJT4lCiAgZGlzdGluY3QoKQoKCmFnZV9zZXhfaW1wYWN0MyAlPiUKICBtdXRhdGVfaWYoaXMuZG91YmxlLCBwZXJjZW50KSAlPiUKICBkYXRhdGFibGUoKQoKZjNjIDwtIGFnZV9zZXhfaW1wYWN0MyAlPiUKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09Ik0iIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0iRiIgfiAiRmVtYWxlIikpICU+JQogIG11dGF0ZShhZ2UgPSBjYXNlX3doZW4oYWdlPT0iMDBfMDUiIH4gIjAgdG8gNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMDZfMTUiIH4gIjA2IHRvIDE1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIxNl8yNSIgfiAiMTYgdG8gMjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjI2XzM1IiB+ICIyNiB0byAzNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMzZfNDUiIH4gIjM2IHRvIDQ1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI0Nl81NSIgfiAiNDYgdG8gNTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjU2XzY1IiB+ICI1NiB0byA2NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNjUrIiB+ICI2NSAmIHVwIHkiKSkgJT4lCiAgZ2dwbG90KCkgKwogICAgZ2VvbV9wb2ludHJhbmdlKGFlcyh5PXBjdF9jaGFuZ2VfZXByZWRfYW5udWFsLCB5bWluPXBjdF9jaGFuZ2VfbG93ZXJfYW5udWFsLCB5bWF4PXBjdF9jaGFuZ2VfdXBwZXJfYW5udWFsLCBncm91cD1hY2ZfcGVyaW9kLCAKICAgICAgICAgICAgICAgICAgICAgIHg9YWdlLAogICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWNmX3BlcmlvZCksIHNpemU9MC4xKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9cGVyY2VudCkgKwogIGZhY2V0X2dyaWQoLn5zZXgpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiI0RFMEQ5MiIsICIjNEQ2Q0ZBIikpICsKICBsYWJzKHg9IiIsCiAgICAgICB5PSJNZWFuIGFubnVhbCByYXRlIG9mIGNoYW5nZSBpbiBjYXNlIG5vdGlmaWNhdGlvbiByYXRlICg5NSUgVUkpXG4gQmVmb3JlIEFDRiAoMTk1MC0xOTU2KSB2cy4gYWZ0ZXIgQUNGICgxOTU4LTE5NjMpIiwKICAgICAgIGNvbG91cj0iIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKZjNjCgpgYGAKCkpvaW4gdG9nZXRoZXIgZm9yIEZpZ3VyZSAyLgoKYGBge3J9CgooZjNhIC8gZjNiIC8gZjNjKSArIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gIkEiKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvZjMucG5nIiksIGhlaWdodD0xMikKCgpgYGAKCgoKSXMgdGhlcmUgYW55IGNvcnJlbGF0aW9uIGJldHdlZW4gaW1tZWRpYXRlIGluY3JlYXNlIGFuZCBhKSBwb3N0LWludGVydmVudGlvbiAoMTk1OCkgZWZmZWN0LCBhbmQgYikgcG9zdCBpbnRlcnZlbnRpb24gc2xvcGUgKDE5NTgtMTk2MykKCmBgYHtyfQoKYWdlX3NleF9jb3JzIDwtIGFnZV9zZXhfaW1wYWN0X291dCAlPiUKICBzZWxlY3QoYWdlLCBzZXgsIGltbWVkaWF0ZV9lZmZlY3QgPSBhY2ZfcnIsCiAgICAgICAgICAgICAgIGltbWVkaWF0ZV9lZmZlY3RfbG93ZXIgPSBhY2ZfcnIubG93ZXIsCiAgICAgICAgICAgICAgIGltbWVkaWF0ZV9lZmZlY3RfdXBwZXIgPSBhY2ZfcnIudXBwZXIpICU+JQogIHJpZ2h0X2pvaW4oCiAgICBhZ2Vfc2V4X2ltcGFjdDIgJT4lIAogICAgICBzZWxlY3QoYWdlLCBzZXgsIHBvc3RfZWZmZWN0ID0gYWNmX3JyLAogICAgICAgICAgICAgICBwb3N0X2VmZmVjdF9sb3dlciA9IGFjZl9yci5sb3dlciwKICAgICAgICAgICAgICAgcG9zdF9lZmZlY3RfdXBwZXIgPSBhY2ZfcnIudXBwZXIpCiAgKSAlPiUKICByaWdodF9qb2luKAogICAgYWdlX3NleF9pbXBhY3QzICU+JQogICAgICBmaWx0ZXIoYWNmX3BlcmlvZD09ImMuIHBvc3QtYWNmIikgJT4lCiAgICAgIHNlbGVjdChhZ2UsIHNleCwgc2xvcGVfZWZmZWN0ID0gcGN0X2NoYW5nZV9lcHJlZCwKICAgICAgICAgICAgIHNsb3BlX2VmZmVjdF9sb3dlciA9IHBjdF9jaGFuZ2VfbG93ZXIsCiAgICAgICAgICAgICBzbG9wZV9lZmZlY3RfdXBwZXIgPSBwY3RfY2hhbmdlX3VwcGVyKQogICkKCmFnZV9zZXhfY29ycyAlPiUKICBtdXRhdGUoYWdlX3NleCA9IHBhc3RlMChzZXgsIGFnZSwgc2VwID0gIiAiKSkgJT4lCiAgZ2dwbG90KGFlcyh4PWltbWVkaWF0ZV9lZmZlY3QsIHhtaW49aW1tZWRpYXRlX2VmZmVjdF9sb3dlciwgeG1heD1pbW1lZGlhdGVfZWZmZWN0X3VwcGVyLAogICAgICAgICAgICAgeT1wb3N0X2VmZmVjdCwgeW1pbj1wb3N0X2VmZmVjdF9sb3dlciwgeW1heD1wb3N0X2VmZmVjdF91cHBlciwKICAgICAgICAgICAgIGdyb3VwID0gYWdlX3NleCwgY29sb3VyPWFnZV9zZXgpKSArCiAgZ2VvbV9lcnJvcmJhcigpICsKICBnZW9tX2Vycm9yYmFyaCgpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgbGFicyh0aXRsZT0iQ29ycmVsYXRpb24gYmV0d2VlbiBpbW1lZGlhdGUgQUNGIGltcGFjdCBhbmQgcG9zdC1BQ0YgY2FzZSBub3RpZmljYXRpb25zIiwKICAgICAgIHk9IlJlbGF0aXZlIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKDE5NTggdnMuIDE5NTYpXG5Qb3N0IGludGVydmVudGlvbiBpbXBhY3QiLAogICAgICAgeD0iUmVsYXRpdmUgY2FzZSBub3RpZmljYXRpb24gcmF0ZSAoMTk1NyB2cy4gMTk1NilcbkltbWVkaWF0ZSBpbXBhY3QiLAogICAgICAgY2FwdGlvbj0iUG9pbnRzIGFyZSBhZ2Utc2V4IGdyb3VwcyIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKYWdlX3NleF9jb3JzICU+JQogIG11dGF0ZShhZ2Vfc2V4ID0gcGFzdGUwKHNleCwgYWdlLCBzZXAgPSAiICIpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9aW1tZWRpYXRlX2VmZmVjdCwgeG1pbj1pbW1lZGlhdGVfZWZmZWN0X2xvd2VyLCB4bWF4PWltbWVkaWF0ZV9lZmZlY3RfdXBwZXIsCiAgICAgICAgICAgICB5PXNsb3BlX2VmZmVjdCwgeW1pbj1zbG9wZV9lZmZlY3RfbG93ZXIsIHltYXg9c2xvcGVfZWZmZWN0X3VwcGVyLAogICAgICAgICAgICAgZ3JvdXAgPSBhZ2Vfc2V4LCBjb2xvdXI9YWdlX3NleCkpICsKICBnZW9tX2Vycm9yYmFyKCkgKwogIGdlb21fZXJyb3JiYXJoKCkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICBsYWJzKHRpdGxlPSJDb3JyZWxhdGlvbiBiZXR3ZWVuIGltbWVkaWF0ZSBBQ0YgaW1wYWN0IGFuZCBwb3N0LUFDRiBtZWFuIHJhdGUgb2YgY2hhbmdlIiwKICAgICAgIHk9IlBvc3QgQUNGIG1lYW4gYW5udWFsIHJhdGUgb2YgY2hhbmdlIGluIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGVzIiwKICAgICAgIHg9IlJlbGF0aXZlIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKDE5NTcgdnMuIDE5NTYpXG5JbW1lZGlhdGUgaW1wYWN0IiwKICAgICAgIGNhcHRpb249IlBvaW50cyBhcmUgbXVuaWNpcGFsd2FyZHMiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCgoKYGBgCgoKCgojIyMgMTEuIERpdmlzaW9uLWxldmVsIG1vZGVsCgooVmVyeSBtdWNoIGEgd29yayBpbiBwcm9ncmVzcyEpCgpgYGB7cn0KCm1kYXRhMyA8LSBkaXZpc2lvbl9pbmMgJT4lCiAgZmlsdGVyKHRiX3R5cGU9PSJQdWxtb25hcnkiKSAlPiUKICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbih5ZWFyICVpbiUgYygxOTUwOjE5NTYpIH4gImEuIHByZS1hY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTcpIH4gImIuIGFjZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciAlaW4lIGMoMTk1ODoxOTYzKSB+ICJjLiBwb3N0LWFjZiIpKSAlPiUKICBncm91cF9ieShkaXZpc2lvbikgJT4lCiAgbXV0YXRlKHlfbnVtID0gcm93X251bWJlcigpKSAlPiUKICB1bmdyb3VwKCkKCgoKYGBgCgoKCmBgYHtyfQoKbTJfcHVsbW9uYXJ5X2RpdmlzaW9uIDwtIGJybSgKICBjYXNlcyB+IHlfbnVtICsgYWNmX3BlcmlvZCArIGFjZl9wZXJpb2Q6eV9udW0gKyAoMSArIHlfbnVtICsgYWNmX3BlcmlvZCArIGFjZl9wZXJpb2Q6eV9udW0gfCBkaXZpc2lvbiAvIHdhcmQpICsgb2Zmc2V0KGxvZyhwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBtZGF0YTIsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0LAogICAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LCBjb3JlcyA9IDQsIAogICAgICAgICAgICAgICAgICBwcmlvciA9IGluZm9ybV9wcmlvcjIsCiAgICAgICAgICAgICAgICAgIHNhdmVfcGFycyA9IHNhdmVfcGFycyhhbGwgPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgYmFja2VuZCA9ICJjbWRzdGFuciIsCiAgICAgICAgICAgICAgICAgIHdhcm11cCA9IDEwMDApCgpzdW1tYXJ5KG0yX3B1bG1vbmFyeV9kaXZpc2lvbikKcGxvdChtMl9wdWxtb25hcnlfZGl2aXNpb24pCnBwX2NoZWNrKG0yX3B1bG1vbmFyeV9kaXZpc2lvbiwgdHlwZT0nZWNkZl9vdmVybGF5JykKCgoKYGBgCgpgYGB7cn0KCiNwb3N0ZXJpb3IgZHJhd3MsIGFuZCBzdW1tYXJpc2UKd2FyZF9wdWxtb25hcnlfc3VtbWFyeTIgPC0gbWRhdGEyICU+JQogIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QsIHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIGluY18xMDBrLCB3YXJkKSAlPiUKICBhZGRfZXByZWRfZHJhd3MobTJfcHVsbW9uYXJ5X3dhcmQpICU+JQogIGdyb3VwX2J5KHllYXIyLCBhY2ZfcGVyaW9kLCB3YXJkKSAlPiUKICBtZWFuX3FpKCkgJT4lCiAgbXV0YXRlKC5lcHJlZF9pbmMgPSAuZXByZWQvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDAsCiAgICAgICAgIC5lcHJlZF9pbmMubG93ZXIgPSAuZXByZWQubG93ZXIvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDAsCiAgICAgICAgIC5lcHJlZF9pbmMudXBwZXIgPSAuZXByZWQudXBwZXIvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDApICU+JQogIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKGFjZl9wZXJpb2Q9PSJhLiBwcmUtYWNmIiB+ICJCZWZvcmUgSW50ZXJ2ZW50aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kPT0iYy4gcG9zdC1hY2YiIH4gIlBvc3QgSW50ZXJ2ZW50aW9uIikpCgojY3JlYXRlIHRoZSBjb3VudGVyZmFjdHVhbCAobm8gaW50ZXJ2ZW50aW9uKSwgYW5kIHN1bW1hcmlzZQp3YXJkX3B1bG1vbmFyeV9jb3VudGVyZmFjdDIgPC0gCiAgdGliYmxlKHllYXIgPSBtZGF0YTIkeWVhciwKICAgICAgICAgeWVhcjIgPSBtZGF0YTIkeWVhcjIsCiAgICAgICAgIHlfbnVtID0gbWRhdGEyJHlfbnVtLAogICAgICAgICB3YXJkID0gbWRhdGEyJHdhcmQsCiAgICAgICAgIGFjZl9wZXJpb2QgPSBmYWN0b3IoImEuIHByZS1hY2YiKSwKICAgICAgICAgcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCA9IG1kYXRhMiRwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSAlPiUKICBhZGRfZXByZWRfZHJhd3MobTJfcHVsbW9uYXJ5X3dhcmQpICU+JQogIGdyb3VwX2J5KHllYXIyLCBhY2ZfcGVyaW9kLCB3YXJkKSAlPiUKICBtZWFuX3FpKCkgJT4lCiAgbXV0YXRlKC5lcHJlZF9pbmMgPSAuZXByZWQvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDAsCiAgICAgICAgIC5lcHJlZF9pbmMubG93ZXIgPSAuZXByZWQubG93ZXIvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDAsCiAgICAgICAgIC5lcHJlZF9pbmMudXBwZXIgPSAuZXByZWQudXBwZXIvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDApICU+JQogIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKGFjZl9wZXJpb2Q9PSJhLiBwcmUtYWNmIiB+ICJCZWZvcmUgSW50ZXJ2ZW50aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kPT0iYy4gcG9zdC1hY2YiIH4gIlBvc3QgSW50ZXJ2ZW50aW9uIikpCgoKCgoKYGBgCgpgYGB7cn0KCndhcmRfcHVsbW9uYXJ5X3N1bW1hcnkyICU+JQogIGRyb3BsZXZlbHMoKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9yaWJib24oYWVzKHltaW49LmVwcmVkX2luYy5sb3dlciwgeW1heD0uZXByZWRfaW5jLnVwcGVyLCB4PXllYXIyLCBncm91cCA9IGFjZl9wZXJpb2QsIGZpbGw9YWNmX3BlcmlvZCksIGFscGhhPTAuNSkgKwogIGdlb21fcmliYm9uKGRhdGEgPSB3YXJkX3B1bG1vbmFyeV9jb3VudGVyZmFjdDIgJT4lIGZpbHRlcih5ZWFyPj0xOTU2KSwgCiAgICAgICAgICAgICAgYWVzKHltaW49LmVwcmVkX2luYy5sb3dlciwgeW1heD0uZXByZWRfaW5jLnVwcGVyLCB4PXllYXIyLCBmaWxsPSJDb3VudGVyZmFjdHVhbCIpLCBhbHBoYT0wLjUpICsKICBnZW9tX2xpbmUoZGF0YSA9IHdhcmRfcHVsbW9uYXJ5X2NvdW50ZXJmYWN0MiAlPiUgZmlsdGVyKHllYXI+PTE5NTYpLCAKICAgICAgICAgICAgICBhZXMoeT0uZXByZWRfaW5jLCB4PXllYXIyLCBjb2xvdXI9IkNvdW50ZXJmYWN0dWFsIikpICsKICBnZW9tX2xpbmUoYWVzKHk9LmVwcmVkX2luYywgeD15ZWFyMiwgZ3JvdXA9YWNmX3BlcmlvZCwgIGNvbG91cj1hY2ZfcGVyaW9kKSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IG1kYXRhMiAsIGFlcyh5PWluY18xMDBrLCB4PXllYXIyLCBzaGFwZT1hY2ZfcGVyaW9kKSwgc2l6ZT0yKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIGZhY2V0X3dyYXAod2FyZH4uKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjREUwRDkyIiwgImdyZXk1MCIsICIjNEQ2Q0ZBIikgLCBuYW1lPSIiKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjREUwRDkyIiwgImdyZXk1MCIsICIjNEQ2Q0ZBIikgLCBuYW1lPSIiKSArCiAgc2NhbGVfc2hhcGVfZGlzY3JldGUobmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBwdWxtb25hcnkgdHViZXJjdWxvc2lzIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUsIGJ5IFdhcmQiLAogICAgc3VidGl0bGUgPSAiRW1waXJpY2FsLCBhbmQgbW9kZWwtcHJlZGljdGVkOiAxOTUwIHRvIDE5NjMiLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiQ2FzZSBub3RpZmljYXRpb24gcmF0ZSAocGVyIDEwMCwwMDApIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1Nylcbk1vZGVsIGVzdGltYXRlcyBmcm9tIEJheWVzaWFuIGludGVycnVwdGVkIHRpbWUgc2VyaWVzIHJlZ3Jlc3Npb24gbW9kZWwiCiAgKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSwKICAgICAgICB0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMikpICsKICBndWlkZXMoc2hhcGU9Im5vbmUiKQogIAoKCmBgYAo=